Quicksort visualization finished.

master
ben-burlingham 10 years ago
parent 4c28ba0029
commit 781d61628d
  1. 6
      index.html
  2. 9
      js/itemgroup.js
  3. 183
      js/quicksort.js
  4. 4
      js/visualizer.js

@ -10,9 +10,8 @@
<body> <body>
for each one: in place? adaptive? stable? swaps. comparisons. random example. best case example. worst case example. for each one: in place? adaptive? stable? swaps. comparisons. random example. best case example. worst case example.
<!-- <h1>Quicksort discussion</h1> <h1>Quicksort discussion</h1>
used by chrome. <br> used by chrome. <br>
swap. highlight. (un)fade.
<div class="sorter" <div class="sorter"
data-algorithm='quick' data-algorithm='quick'
data-stable='Maybe' data-stable='Maybe'
@ -22,12 +21,11 @@
data-best-perf='O(n + m + 3k)' data-best-perf='O(n + m + 3k)'
data-worst-memory='0 (in place)' data-worst-memory='0 (in place)'
></div> ></div>
-->
<h1>Mergesort discussion</h1> <h1>Mergesort discussion</h1>
used by firefox and safari. <br> used by firefox and safari. <br>
helpful: http://stackoverflow.com/questions/2967153/space-requirements-of-a-merge-sort<br> helpful: http://stackoverflow.com/questions/2967153/space-requirements-of-a-merge-sort<br>
<div class="sorter" <div class="sorter"
data-algorithm='merge' data-algorithm='merge'
data-stable='Maybe' data-stable='Maybe'

@ -58,11 +58,14 @@ var Itemgroup = {
if (i === indexA) { if (i === indexA) {
x = indexB * (Visualizer.itemW + Visualizer.spacerW) + Visualizer.padding; x = indexB * (Visualizer.itemW + Visualizer.spacerW) + Visualizer.padding;
a = d3.select(this).select('text').text(); a = d3.select(this).select('text').text();
if (indexA === indexB) {
b = a;
}
} }
else if (i === indexB) { else if (i === indexB) {
x = indexA * (Visualizer.itemW + Visualizer.spacerW) + Visualizer.padding; x = indexA * (Visualizer.itemW + Visualizer.spacerW) + Visualizer.padding;
b = d3.select(this).select('text').text(); b = d3.select(this).select('text').text();
} }
return `translate(${x}, ${Visualizer.padding})`; return `translate(${x}, ${Visualizer.padding})`;
@ -72,8 +75,6 @@ var Itemgroup = {
return; return;
} }
console.log(`indexA: ${indexA}, ${a}, indexB: ${indexB}, ${b}`);
// Undo the animation by restoring the original positions and swapping the values. // Undo the animation by restoring the original positions and swapping the values.
group.selectAll('g') group.selectAll('g')
.attr('transform', function transform(d, i) { .attr('transform', function transform(d, i) {
@ -88,8 +89,6 @@ var Itemgroup = {
d3.select(this).select('text').text(a); d3.select(this).select('text').text(a);
} }
}); });
console.warn(`indexA: ${indexA}, ${a}, indexB: ${indexB}, ${b}`);
}); });
}, },

@ -1,27 +1,123 @@
/** /**
* *
*/ */
var QuickSort = function(VisualizerInstance) { var QuickSort = function() {
//===== Inits.
this.actions = [];
this.swaps = 0; this.swaps = 0;
this.comparisons = 0; this.comparisons = 0;
this.V = VisualizerInstance;
this.V //===== Action management.
.instruct(this.V.hideMarker, 0, 1) //
.instruct(this.V.hideMarker, 0, 2) this.preSort = function(left, right, pivot, len) {
.instruct(this.V.message, 0, 2, 'Swaps: ' + this.swaps) this
.instruct(this.V.message, 0, 1, 'Comparisons: ' + this.comparisons); .instruct(Itemgroup.message, 0, 0, 1, 'Comparisons: ' + this.comparisons)
.instruct(Itemgroup.message, 0, 0, 2, 'Swaps: ' + this.swaps)
.instruct(Itemgroup.opacity, 1, 0, 0, len, 1)
.instruct(Itemgroup.opacity, 1, 0, -1, left - 1, 0.2)
.instruct(Itemgroup.opacity, 1, 0, right + 1, len, 0.2)
.instruct(Itemgroup.background, 1, 0, 0, this.ordered.length, Visualizer.bg0)
.instruct(Itemgroup.message, 0, 0, 3, 'Sorting from [' + left + '] to [' + right + ']')
.instruct(Itemgroup.message, 0, 0, 4, '')
.instruct(Itemgroup.message, 0, 100, 5, '');
};
//
this.highlight = function(arr, left, right, pivot, msg) {
if (left >= right) {
return;
}
this
.instruct(Itemgroup.background, 1, 0, 0, arr.length, Visualizer.bg0)
.instruct(Itemgroup.background, 1, 0, pivot, pivot, '#435C11')
.instruct(Itemgroup.background, 1, 0, left, left, '#0C1E42')
.instruct(Itemgroup.background, 1, 0, right, right, '#7F9EDB')
.instruct(Itemgroup.message, 0, 0, 1, `Comparisons: ${this.comparisons}`)
.instruct(Itemgroup.message, 0, 0, 4, `Pivot at [${pivot}] = ${arr[pivot]}`)
.instruct(Itemgroup.message, 0, 100, 5, msg)
// .instruct(Itemgroup.message, 0, 0, 5, msg)
// .instruct(Itemgroup.message, 0, 100, 1, `Comparisons: ${this.comparisons}`)
};
//
this.stop = function(arr, left, right, pivot, msg) {
this
.instruct(Itemgroup.background, 1, 0, 0, arr.length, Visualizer.bg0)
.instruct(Itemgroup.background, 1, 0, pivot, pivot, '#435C11')
.instruct(Itemgroup.background, 1, 0, left, left, '#0C1E42')
.instruct(Itemgroup.background, 1, 0, right, right, '#7F9EDB')
.instruct(Itemgroup.message, 0, 0, 4, `Pivot at [${pivot}] = ${arr[pivot]}`)
.instruct(Itemgroup.message, 0, 100, 5, msg)
};
//
this.swap = function(left, right) {
this
.instruct(Itemgroup.message, 0, 0, 2, 'Swaps: ' + this.swaps)
.instruct(Itemgroup.message, 0, 0, 4, 'Incremement left...')
.instruct(Itemgroup.message, 0, 0, 5, 'Decrement right...')
.instruct(Itemgroup.swap, 1, 300, left, right)
};
//
this.midSort = function(start, end, left, right) {
this
.instruct(Itemgroup.message, 0, 0, 3, 'Left has passed right.')
.instruct(Itemgroup.message, 0, 0, 4, `Recurse, sort from [${start}]-[${right}]`)
.instruct(Itemgroup.message, 0, 100, 5, `Recurse, sort from [${left}]-[${end}]`);
};
//
this.postSort = function() {
this
.instruct(Itemgroup.opacity, 1, 0, 0, this.ordered.length, 1)
.instruct(Itemgroup.background, 1, 0, 0, this.ordered.length, Visualizer.bg0)
.instruct(Itemgroup.message, 0, 0, 3, 'Sorting complete.')
.instruct(Itemgroup.message, 0, 0, 4, '')
.instruct(Itemgroup.message, 0, 0, 5, '');
};
}; };
QuickSort.prototype = Object.create(Sorter.prototype); QuickSort.prototype = Object.create(Sorter.prototype);
// NOTE adds to an instruction set /**
*
*/
QuickSort.prototype.init = function() {
var len = this.shuffled.length;
this
.instruct(Itemgroup.items, 0, 0, len)
.instruct(Itemgroup.items, 1, 0, len)
.instruct(Itemgroup.items, 2, 0, len)
for (var i = 0; i < len; i++) {
this.instruct(Itemgroup.text, 1, 0, i, this.shuffled[i]);
}
this
.instruct(Itemgroup.foreground, 1, 0, 0, len, Visualizer.fg0)
.instruct(Itemgroup.background, 1, 0, 0, len, Visualizer.bg0)
.instruct(Itemgroup.opacity, 0, 0, 0, len, 0)
.instruct(Itemgroup.opacity, 2, 0, 0, len, 0)
};
/** /**
* *
*/ */
QuickSort.prototype.sort = function(arr, start, end) { QuickSort.prototype.sort = function(arr, start, end) {
if (end <= start) { if (end <= start) {
// message: Left and Right have crossed, start sorting sublists. // message: Left and Right have crossed, start sorting sublists.
this.postSort();
return arr; return arr;
} }
@ -29,94 +125,49 @@ QuickSort.prototype.sort = function(arr, start, end) {
var right = end; var right = end;
var pivot = Math.floor((right + left) / 2); var pivot = Math.floor((right + left) / 2);
var pivotval = arr[pivot].value; var pivotval = arr[pivot];
var tmp; var tmp;
var rval; var rval;
this.V // Message: pivot chosen
.instruct(this.V.marker, 0, 1, left, 'L') this.preSort(left, right, pivot, arr.length);
.instruct(this.V.marker, 0, 2, right, 'R')
.instruct(this.V.showMarker, 0, 1)
.instruct(this.V.showMarker, 0, 2)
.instruct(this.V.unhighlight, 0)
.instruct(this.V.highlight, 0, pivot)
.instruct(this.V.fade, 0, -1, start - 1)
.instruct(this.V.fade, 0, end + 1, arr.length)
// Message: pivot chosen
.instruct(this.V.message, 0, 3, 'Sorting from [' + start + '] to [' + end + ']')
.instruct(this.V.message, 0, 4, '')
.instruct(this.V.message, 100, 5, '');
while (left <= right) { while (left <= right) {
while (arr[left] < pivotval) {
this.V.instruct(this.V.message, 0, 4, '');
this.V.instruct(this.V.message, 0, 5, '');
while (arr[left].value < pivotval) {
this.comparisons++; this.comparisons++;
this.V this.highlight(arr, left, right, pivot, `${arr[left]} < ${arr[pivot]}, increment left`);
.instruct(this.V.message, 0, 4, `${arr[left].value} < ${pivotval}, increment left` )
.instruct(this.V.message, 0, 1, `Comparisons: ${this.comparisons}`)
.instruct(this.V.marker, 500, 1, left);
left++; left++;
} }
this.V this.stop(arr, left, right, pivot, `Left stop: ${arr[left]} >= ${arr[pivot]}`);
.instruct(this.V.message, 0, 4, `Left stop: ${arr[left].value} >= ${pivotval}`)
.instruct(this.V.marker, 500, 1, left);
while (arr[right].value > pivotval) { while (arr[right] > pivotval) {
this.comparisons++; this.comparisons++;
this.V this.highlight(arr, left, right, pivot, `${arr[right]} > ${arr[pivot]}, decrement right`);
.instruct(this.V.message, 0, 5, `${arr[right].value} > ${pivotval}, decrement right`)
.instruct(this.V.message, 0, 1, 'Comparisons: ' + this.comparisons)
.instruct(this.V.marker, 100, 2, right);
right--; right--;
} }
this.V this.stop(arr, left, right, pivot, `Right stop: ${arr[right]} <= ${arr[pivot]} `);
.instruct(this.V.message, 0, 5, `Right stop: ${arr[right].value} <= ${pivotval} `)
.instruct(this.V.marker, 100, 2, right);
if (left <= right) { if (left <= right) {
tmp = arr[left]; tmp = arr[left];
arr[left] = arr[right]; arr[left] = arr[right];
arr[right] = tmp; arr[right] = tmp;
this.V.instruct(this.V.swap, 100, left, right);
left++; left++;
right--; right--;
this.swaps++; this.swaps++;
this.V this.swap(left - 1, right + 1);
.instruct(this.V.message, 0, 2, 'Swaps: ' + this.swaps)
.instruct(this.V.message, 0, 4, 'Incremement left...')
.instruct(this.V.message, 0, 5, 'Decrement right...')
.instruct(this.V.marker, 100, 1, left)
.instruct(this.V.marker, 100, 2, right)
} }
} }
this.V this.midSort(start, end, left, right);
.instruct(this.V.unfade, 0)
.instruct(this.V.unhighlight, 0)
.instruct(this.V.hideMarker, 0, 1)
.instruct(this.V.hideMarker, 0, 2)
.instruct(this.V.message, 0, 3, 'Sorting complete.')
.instruct(this.V.message, 0, 4, '')
.instruct(this.V.message, 0, 5, '');
this.sort(arr, start, right); this.sort(arr, start, right);
this.sort(arr, left, end); this.sort(arr, left, end);
this.postSort();
return arr; return arr;
}; };

@ -98,11 +98,11 @@ Visualizer.prototype.go = function() {
// TODO add tabs for best/worst cases // TODO add tabs for best/worst cases
// TODO add links to stats // TODO add links to stats
// TODO fix init slider // TODO fix init slider and match to width
// TODO heap sort // TODO heap sort
// TODO extra memory // TODO extra memory
// TODO width update
// TODO disable next button if no further actions and during action // TODO disable next button if no further actions and during action
// TODO source code tab
// NOTE functional programming discussion // NOTE functional programming discussion
// NOTE interesting (anti?)pattern here. // NOTE interesting (anti?)pattern here.

Loading…
Cancel
Save