2
2
3
3
function color ( x , width ) {
4
4
return d3 . interpolateViridis ( x / width ) ;
5
- // return "hsla(" + (x / width * 360) + ", 100%, 50%, 1.0)";
6
- //return "RGB(" + (x / width * 255) + ", 0, 0)";
7
5
}
8
6
9
7
function shuffle ( array , start , end ) {
@@ -20,10 +18,6 @@ var SG_MAGICCONST = 1.0 + Math.log(4.5);
20
18
var LOG4 = Math . log ( 4.0 ) ;
21
19
22
20
function gamma_distribution ( alpha , beta ) {
23
- /*if (alpha <= 0.0 || beta <= 0.0) {
24
- throw new Error('gamma_distribution: alpha and beta must be > 0.0');
25
- }*/
26
-
27
21
if ( alpha > 1 ) {
28
22
var ainv = Math . sqrt ( 2.0 * alpha - 1.0 ) ;
29
23
var bbb = alpha - LOG4 ;
@@ -99,6 +93,7 @@ function SortingVisualization(data, options, ctx) {
99
93
}
100
94
101
95
this . data = data ;
96
+ this . captures = [ ] ;
102
97
103
98
this . options = options ;
104
99
this . ctx = ctx ;
@@ -203,6 +198,26 @@ InsertionSort.prototype.sort = function(y, left, right) {
203
198
}
204
199
} ;
205
200
201
+ function StoogeSort ( ) {
202
+ SortingVisualization . apply ( this , arguments ) ;
203
+ }
204
+
205
+ StoogeSort . prototype = Object . create ( SortingVisualization . prototype ) ;
206
+ StoogeSort . prototype . constructor = SortingVisualization ;
207
+
208
+ StoogeSort . prototype . sort = function ( y , left , right ) {
209
+ if ( this . cmp ( this . data [ y ] [ right ] , this . data [ y ] [ left ] ) ) {
210
+ this . swap ( y , left , right ) ;
211
+ }
212
+
213
+ if ( right - left >= 2 ) {
214
+ var t = Math . round ( ( right - left ) / 3 ) ;
215
+ this . sort ( y , left , right - t ) ;
216
+ this . sort ( y , left + t , right ) ;
217
+ this . sort ( y , left , right - t ) ;
218
+ }
219
+ } ;
220
+
206
221
function SelectionSort ( ) {
207
222
SortingVisualization . apply ( this , arguments ) ;
208
223
}
@@ -305,6 +320,30 @@ ShellSort.prototype.sort = function(y, left, right) {
305
320
}
306
321
} ;
307
322
323
+ function CombSort ( ) {
324
+ SortingVisualization . apply ( this , arguments ) ;
325
+ }
326
+
327
+ CombSort . prototype = Object . create ( SortingVisualization . prototype ) ;
328
+ CombSort . prototype . constructor = SortingVisualization ;
329
+
330
+ CombSort . prototype . sort = function ( y , left , right ) {
331
+ var gap = right - left ;
332
+ var sorted = false ;
333
+
334
+ while ( ! sorted ) {
335
+ gap = Math . max ( Math . floor ( gap / options . shrink_factor ) , 1 ) ;
336
+ sorted = gap === 1 ;
337
+
338
+ for ( var i = left ; i + gap <= right ; i ++ ) {
339
+ if ( this . cmp ( this . data [ y ] [ i + gap ] , this . data [ y ] [ i ] ) ) {
340
+ sorted = false ;
341
+ this . swap ( y , i , i + gap ) ;
342
+ }
343
+ }
344
+ }
345
+ } ;
346
+
308
347
function QuickSort ( ) {
309
348
SortingVisualization . apply ( this , arguments ) ;
310
349
}
@@ -410,27 +449,44 @@ document.addEventListener('DOMContentLoaded', function() {
410
449
var canvas = document . getElementById ( 'canvas' ) ;
411
450
var ctx = canvas . getContext ( '2d' ) ;
412
451
452
+ var canvas2 = document . getElementById ( 'canvas-2' ) ;
453
+ var ctx2 = canvas2 . getContext ( '2d' ) ;
454
+ var canvas2dl = document . getElementById ( 'canvas-2-dl' ) ;
455
+ canvas2dl . addEventListener (
456
+ 'click' ,
457
+ function ( ) {
458
+ var dt = canvas2 . toDataURL ( 'image/png' ) ;
459
+ this . href = dt ;
460
+ } ,
461
+ false ,
462
+ ) ;
463
+
413
464
var processing = false ;
414
465
466
+ var desiredCaptures = 100 ;
467
+
415
468
var data , sort_visualization ;
416
469
417
470
var algorithms = {
418
471
'Bubble sort' : BubbleSort ,
419
472
'Insertion sort' : InsertionSort ,
473
+ 'Stooge sort' : StoogeSort ,
420
474
'Selection sort' : SelectionSort ,
421
475
'Cocktail sort' : CocktailSort ,
422
476
'Odd-even sort' : OddEvenSort ,
423
477
'Shell sort' : ShellSort ,
478
+ 'Comb sort' : CombSort ,
424
479
'Quick sort' : QuickSort ,
425
480
'Heap sort' : HeapSort ,
426
481
} ;
427
482
428
483
options = {
429
484
width : 100 ,
430
- height : 100 ,
485
+ height : 1 ,
431
486
speed : 1 ,
432
487
algorithm : 'Bubble sort' ,
433
488
pivot : 'Start' ,
489
+ shrink_factor : 1.3 ,
434
490
generate : 'Increasing' ,
435
491
shuffle : function ( ) {
436
492
for ( var y = 0 ; y < data . length ; y ++ ) {
@@ -440,6 +496,7 @@ document.addEventListener('DOMContentLoaded', function() {
440
496
} ,
441
497
zoom : 4 ,
442
498
start : function ( ) {
499
+ options . shuffle ( ) ;
443
500
hide_gui_element ( 'shuffle' , true ) ;
444
501
hide_gui_element ( 'start' , true ) ;
445
502
hide_gui_element ( 'stop' , false ) ;
@@ -449,17 +506,38 @@ document.addEventListener('DOMContentLoaded', function() {
449
506
var algorithm = algorithms [ options . algorithm ] ;
450
507
sort_visualization = new algorithm ( data , options , ctx ) ;
451
508
509
+ options . capture ( ) ;
510
+
452
511
for ( var y = 0 ; y < options . height ; y ++ ) {
453
512
sort_visualization . sort ( y , 0 , options . width - 1 ) ;
454
513
}
455
514
sort_visualization . sort_end ( ) ;
456
515
516
+ var currentFrame = 1 ;
517
+ var totalFrames = d3 . max ( sort_visualization . swaps , swap => swap . length ) ;
518
+ var scale = d3
519
+ . scaleLinear ( )
520
+ . domain ( [ 0 , desiredCaptures - 1 ] )
521
+ . range ( [ 0 , totalFrames ] ) ;
522
+ var captureFrames = d3
523
+ . range ( 1 , desiredCaptures )
524
+ . map ( scale )
525
+ . map ( Math . round ) ;
526
+
457
527
function step ( ) {
458
528
if ( ! processing ) {
459
529
return ;
460
530
}
461
- for ( var i = 0 ; i < options . speed ; i ++ ) {
462
- if ( sort_visualization . step ( ) ) {
531
+ for ( var i = 0 , done ; i < options . speed ; i ++ ) {
532
+ done = sort_visualization . step ( ) ;
533
+
534
+ if ( captureFrames [ 0 ] === currentFrame ) {
535
+ captureFrames . shift ( ) ;
536
+ options . capture ( ) ;
537
+ }
538
+ currentFrame ++ ;
539
+
540
+ if ( done ) {
463
541
options . stop ( ) ;
464
542
return ;
465
543
}
@@ -476,16 +554,57 @@ document.addEventListener('DOMContentLoaded', function() {
476
554
477
555
data = sort_visualization . data ;
478
556
557
+ options . renderCaptures ( ) ;
558
+
479
559
processing = false ;
480
560
} ,
561
+ capture : function ( ) {
562
+ sort_visualization . captures . push (
563
+ ctx . getImageData ( 0 , 0 , canvas . width , canvas . height ) ,
564
+ ) ;
565
+ } ,
566
+ renderCaptures : function ( ) {
567
+ var newCaptures = sort_visualization . captures ;
568
+ var renderHeight = Math . floor ( canvas2 . height / desiredCaptures ) ;
569
+
570
+ // Changes rendering algorithm
571
+ var alwaysRenderFirstRow = true ;
572
+
573
+ for ( var i = 0 ; i < newCaptures . length ; i ++ ) {
574
+ if ( alwaysRenderFirstRow ) {
575
+ ctx2 . putImageData (
576
+ newCaptures [ i ] ,
577
+ 0 , // dx,
578
+ i * renderHeight , // dy,
579
+ 0 , // dirtyX, - dest x pos
580
+ 0 , // dirtyY, - dest y pos
581
+ canvas2 . width , // dirtyWidth,
582
+ renderHeight * options . zoom , // dirtyHeight
583
+ ) ;
584
+ } else {
585
+ ctx2 . putImageData (
586
+ newCaptures [ i ] ,
587
+ 0 , // dx,
588
+ 0 , // dy,
589
+ 0 , // dirtyX, - dest x pos
590
+ i * renderHeight , // dirtyY, - dest y pos
591
+ canvas2 . width , // dirtyWidth,
592
+ renderHeight , // dirtyHeight
593
+ ) ;
594
+ }
595
+ }
596
+ } ,
481
597
distribution : {
482
598
alpha : 1 ,
483
599
beta : 1 ,
484
600
} ,
485
601
} ;
486
602
487
603
function draw ( use_visualization_data ) {
488
- var draw_data = use_visualization_data ? sort_visualization . data : data ;
604
+ var draw_data =
605
+ use_visualization_data && sort_visualization
606
+ ? sort_visualization . data
607
+ : data ;
489
608
canvas . width = options . width * options . zoom ;
490
609
canvas . height = options . height * options . zoom ;
491
610
@@ -503,6 +622,13 @@ document.addEventListener('DOMContentLoaded', function() {
503
622
) ;
504
623
}
505
624
}
625
+
626
+ canvas2 . width = canvas . width ;
627
+ canvas2 . height = desiredCaptures * options . zoom ;
628
+ canvas2 . style . width = canvas2 . width + 'px' ;
629
+ canvas2 . style . height = canvas2 . height + 'px' ;
630
+ ctx2 . fillStyle = '#cccccc' ;
631
+ ctx2 . fillRect ( 0 , 0 , canvas2 . width , canvas2 . height ) ;
506
632
}
507
633
508
634
function resize ( ) {
@@ -544,14 +670,16 @@ document.addEventListener('DOMContentLoaded', function() {
544
670
. name ( 'Algorithm' )
545
671
. onChange ( function ( ) {
546
672
hide_gui_element ( 'pivot' , options . algorithm !== 'Quick sort' ) ;
673
+ hide_gui_element ( 'shrink_factor' , options . algorithm !== 'Comb sort' ) ;
547
674
} ) ;
548
675
gui . add ( options , 'pivot' , [ 'Start' , 'Middle' , 'End' , 'Random' ] ) . name ( 'Pivot' ) ;
676
+ gui . add ( options , 'shrink_factor' , 1.001 , 3 ) . name ( 'Shrink factor' ) ;
549
677
gui
550
678
. add ( options , 'generate' , [ 'Increasing' , 'Decreasing' ] )
551
679
. name ( 'Generate' )
552
680
. onChange ( resize ) ;
553
681
gui . add ( options , 'shuffle' ) . name ( 'Shuffle' ) ;
554
- gui . add ( options , 'zoom' , 1 , 10 , 1 ) . name ( 'Zoom' ) . onChange ( function ( ) {
682
+ gui . add ( options , 'zoom' , 1 , 50 , 1 ) . name ( 'Zoom' ) . onChange ( function ( ) {
555
683
draw ( true ) ;
556
684
} ) ;
557
685
gui . add ( options , 'start' ) . name ( 'Start' ) ;
@@ -573,4 +701,5 @@ document.addEventListener('DOMContentLoaded', function() {
573
701
574
702
hide_gui_element ( 'stop' , true ) ;
575
703
hide_gui_element ( 'pivot' , true ) ;
704
+ hide_gui_element ( 'shrink_factor' , true ) ;
576
705
} ) ;
0 commit comments