Finalizing instruction set for quicksort.

master
ben-burlingham 10 years ago
parent 9bd76056b6
commit 1010f74cff
  1. 12
      index.html
  2. 99
      js/quicksort.js
  3. 61
      js/visualizer-actions.js
  4. 34
      js/visualizer-inits.js
  5. 76
      js/visualizer.js

@ -98,7 +98,7 @@
}
.controls-container {
height:50px;
height:45px;
padding-bottom:10px;
text-align:center;
}
@ -135,7 +135,6 @@
.message-container {
border-top:1px solid #ddd;
font-size:13px;
height:100px;
line-height:20px;
text-align:right;
@ -143,23 +142,22 @@
.message-container .message {
border-bottom:1px solid #ddd;
font-size:13px;
font-size:12px;
}
.range-container {
height:50px;
margin-top:30px;
margin-top:40px;
text-align:center;
}
.range-container input {
margin-bottom:10px;
margin-bottom:5px;
}
.range-container .msg {
font-size:13px;
font-size:11px;
}
</style>
</head>
<body>

@ -1,28 +1,27 @@
/**
*
*/
var QuickSort = function() {
this.instructions = [];
var QuickSort = function(Visualizer) {
this.swaps = 0;
this.comparisons = 0;
this.V = Visualizer;
this.V
.instruct(this.V.message, 0, 2, 'Swaps: ' + this.swaps)
.instruct(this.V.message, 0, 1, 'Comparisons: ' + this.comparisons);
};
QuickSort.prototype = Object.create(Sorter.prototype);
QuickSort.prototype.instruct = function() {
this.instructions.push(arguments);
return this;
};
// NOTE adds to an instruction set
/**
*
*/
QuickSort.prototype.sort = function(arr, start, end) {
if (end - start <= 0) {
// this//.instruct('highlight', 500, end)
// .instruct('message', 0, 3, 'Start: ' + start)
// .instruct('message', 0, 4, 'End: ' + end)
// this//.instruct(this.V.highlight, 500, end)
// .instruct(this.V.message, 0, 3, 'Start: ' + start)
// .instruct(this.V.message, 0, 4, 'End: ' + end)
return arr;
}
@ -32,60 +31,82 @@ QuickSort.prototype.sort = function(arr, start, end) {
var pivot = Math.floor((right + left) / 2);
var pivotval = arr[pivot].value;
var tmp;
var rval;
this.V
.instruct(this.V.marker, 0, 1, left, 'L')
.instruct(this.V.marker, 0, 2, right, 'R')
.instruct(this.V.showMarker, 0, 1)
.instruct(this.V.showMarker, 0, 2)
this//.instruct('initSection', left, right)
.instruct('showMarker', 0, 1)
.instruct('marker', 0, 1, left, 'L')
.instruct('message', 0, 3, 'Left: ' + left)
.instruct('showMarker', 0, 2)
.instruct('marker', 0, 2, right, 'R')
.instruct('message', 0, 4, 'Right: ' + right)
.instruct('unhighlight')
.instruct('highlight', 100, pivot)
.instruct('message', 0, 5, 'Pivot value: ' + pivotval + ', pivot index: ' + pivot);
.instruct(this.V.unhighlight, 0)
.instruct(this.V.highlight, 0, pivot)
.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 (arr[left].value < pivotval) {
left++;
this.V.instruct(this.V.message, 0, 4, '');
this.V.instruct(this.V.message, 0, 5, '');
while (arr[left].value < pivotval) {
this.comparisons++;
this.instruct('marker', 100, 1, left)
.instruct('message', 0, 3, 'Left: ' + left)
.instruct('message', 0, 1, 'Comparisons: ' + this.comparisons)
this.V
.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++;
}
while (arr[right].value > pivotval) {
right--;
this.V
.instruct(this.V.message, 0, 4, `Left stop: ${arr[left].value} >= ${pivotval}`)
.instruct(this.V.marker, 500, 1, left);
while (arr[right].value > pivotval) {
this.comparisons++;
this.instruct('marker', 100, 2, right)
.instruct('message', 0, 4, 'Right: ' + right)
.instruct('message', 0, 1, 'Comparisons: ' + this.comparisons)
this.V
.instruct(this.V.message, 0, 5, `${arr[right].value} < ${pivotval}, decrement right`)
.instruct(this.V.message, 0, 1, 'Comparisons: ' + this.comparisons)
right--;
this.V.instruct(this.V.marker, 500, 2, right)
}
this.V.instruct(this.V.message, 100, 5, `Right stop: ${arr[right].value} <= ${pivotval} `)
if (left <= right) {
tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
this.instruct('swap', 500, left, right);
this.V.instruct(this.V.swap, 500, left, right);
left++;
right--;
this.swaps++;
this.instruct('message', 0, 2, 'Swaps: ' + this.swaps)
.instruct('marker', 100, 1, left)
.instruct('message', 0, 3, 'Left: ' + left)
.instruct('marker', 100, 2, right)
.instruct('message', 0, 4, 'Right: ' + right);
this.V
.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.instruct('unhighlight', 0)
.instruct('hideMarker', 0, 1)
.instruct('hideMarker', 0, 2);
this.V
.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, left, end);

@ -1,15 +1,12 @@
/**
*
*/
Visualizer.prototype.swap = function(args) {
var indexA = args[2];
var indexB = args[3];
Visualizer.prototype.swap = function(delay, indexA, indexB) {
// NOTE Two way binding here between dataset and function parameter?
// NOTE swapping will not reorder index and i parameter will be off
// NOTE discuss chained transitions: http://bl.ocks.org/mbostock/1125997
this.groups
.transition().duration(400)
.transition().duration(delay)
.attr('transform', function doTransform(d) {
if (d.index === indexA) {
d.index = indexB;
@ -19,15 +16,13 @@ Visualizer.prototype.swap = function(args) {
}
return `translate(${Visualizer.calculateX(d.index)}, ${Visualizer.itemY})`;
})
});
};
/**
* Highlights an index.
*/
Visualizer.prototype.highlight = function(args) {
var index = args[2];
Visualizer.prototype.highlight = function(delay, index) {
if (index < 0) {
console.error('Trying to highlight index of ' + index);
return;
@ -47,12 +42,6 @@ Visualizer.prototype.unhighlight = function() {
this.svg.selectAll('.item').attr('fill', function(d) { return d.fill; });
};
// TODO restart instructions on re-init
// TODO add tabs for best/worst cases
// TODO add links to stats
// TODO fade unfade
// TODO try to pass reference instead of string, use apply() or call()?
// /**
// * Greys out an item.
// */
@ -83,28 +72,21 @@ Visualizer.prototype.unhighlight = function() {
/**
*
*/
Visualizer.prototype.hideMarker = function(args) {
var which = args[2];
Visualizer.prototype.hideMarker = function(delay, which) {
this.svg.select(`#marker${which}`).attr('style', 'display:none');
};
/**
*
*/
Visualizer.prototype.showMarker = function(args) {
var which = args[2];
Visualizer.prototype.showMarker = function(delay, which) {
this.svg.select(`#marker${which}`).attr('style', 'display:block');
};
/**
* Marker movement.
*/
Visualizer.prototype.marker = function(args) {
var delay = args[1];
var which = args[2];
var index = args[3];
var label = args[4];
Visualizer.prototype.marker = function(delay, which, index, label) {
if (label !== undefined) {
label = label[0].toString();
this.svg.select(`#marker${which} text`).text(label)
@ -118,8 +100,31 @@ Visualizer.prototype.marker = function(args) {
/**
* Message updates.
*/
Visualizer.prototype.message = function(args) {
var which = args[2];
var msg = args[3];
Visualizer.prototype.message = function(delay, which, msg) {
var msg = msg || '&nbsp;';
this.parent.querySelector(`.message:nth-child(${which})`).innerHTML = msg;
};
/**
*
*/
Visualizer.prototype.reset = function() {
this.instructionIndex = 0;
this.message([null, 0, 1, '']);
this.message([null, 0, 2, '']);
this.message([null, 0, 3, '']);
this.message([null, 0, 4, '']);
this.message([null, 0, 5, '']);
this.marker([null, 0, 1, 0]);
this.marker([null, 0, 2, 0]);
this.unhighlight();
this.groups
.transition().duration(100)
.attr('transform', function doTransform(d, i) {
d.index = i;
return `translate(${Visualizer.calculateX(i)}, ${Visualizer.itemY})`;
});
};

@ -1,3 +1,5 @@
'use strict';
/**
*
*/
@ -95,17 +97,15 @@ Visualizer.prototype.initMessages = function() {
var div4 = document.createElement('div');
div4.className = 'message';
div4.innerHTML = 'Comparisons: 0';
var div5 = document.createElement('div');
div5.className = 'message';
div5.innerHTML = 'Swaps: 0';
div1.innerHTML = 'testing';
div2.innerHTML = 'testing';
div3.innerHTML = 'testing';
div4.innerHTML = 'testing';
div5.innerHTML = 'testing';
div1.innerHTML = '&nbsp;';
div2.innerHTML = '&nbsp;';
div3.innerHTML = '&nbsp;';
div4.innerHTML = '&nbsp;';
div5.innerHTML = '&nbsp;';
container.appendChild(div1);
container.appendChild(div2);
@ -153,22 +153,33 @@ Visualizer.prototype.initRange = function() {
*
*/
Visualizer.prototype.initControls = function() {
var _this = this;
var updatePlayPause = function(paused) {
if (paused === true) {
play.className = 'fa fa-pause';
play.className = 'fa fa-play';
}
else {
play.className = 'fa fa-play';
play.className = 'fa fa-pause';
}
};
var playclick = function() {
this.paused = !this.paused;
updatePlayPause(this.paused);
this.followInstruction();
if (this.instructionIndex === this.instructions.length) {
this.reset();
this.paused = false;
this.followInstruction();
}
else {
this.followInstruction();
}
};
var backclick = function() {
// TODO followinstruction skips delay of 0
this.paused = true;
this.instructionIndex--;
this.followInstruction();
@ -183,8 +194,7 @@ Visualizer.prototype.initControls = function() {
var restartclick = function() {
this.paused = false;
updatePlayPause(this.paused);
this.instructionIndex = 0;
this.followInstruction();
this.reset();
};
var play = document.createElement('button');

@ -2,6 +2,7 @@
*
*/
function Visualizer(parent) {
this.instructions = [];
this.parent = parent;
this.sorter = null;
this.paused = true;
@ -24,31 +25,31 @@ function Visualizer(parent) {
switch(parent.attributes['data-algorithm'].value) {
case 'quick':
this.sorter = new QuickSort();
this.sorter = new QuickSort(this);
break;
case 'merge':
this.sorter = new MergeSort();
this.sorter = new MergeSort(this);
break;
case 'selection':
this.sorter = new SelectionSort();
this.sorter = new SelectionSort(this);
break;
case 'bubble':
this.sorter = new BubbleSort();
this.sorter = new BubbleSort(this);
break;
case 'insertion':
this.sorter = new InsertionSort();
this.sorter = new InsertionSort(this);
break;
case 'shell':
this.sorter = new ShellSort();
this.sorter = new ShellSort(this);
break;
case 'radix':
this.sorter = new RadixSort();
this.sorter = new RadixSort(this);
break;
default:
@ -58,49 +59,72 @@ function Visualizer(parent) {
this.initItems(10);
};
// Public static properties (mutable)
// Static properties (mutable)
Visualizer.spacerW = 5;
Visualizer.itemW = 14;
Visualizer.itemH = 50;
Visualizer.itemY = 20;
/**
*
* Static.
*/
Visualizer.calculateX = function(index) {
return Visualizer.spacerW + index * (Visualizer.itemW + Visualizer.spacerW)
};
/**
*
*/
Visualizer.prototype.instruct = function() {
this.instructions.push(arguments);
return this;
};
/**
* Instructions contain a string with the name of a function in this object which is called to perform an action.
*/
Visualizer.prototype.followInstruction = function() {
if (this.instructionIndex >= this.sorter.instructions.length) {
if (this.instructionIndex >= this.instructions.length) {
return;
}
var instruction = this.sorter.instructions[this.instructionIndex];
var operation = this[instruction[0]];
var obj = this.instructions[this.instructionIndex];
var instruction = new Array();
for (var key in obj) {
if (obj[key].hasOwnProperty) {
instruction.push(obj[key]);
}
}
var delay = instruction[1];
var args = instruction.slice(1);
console.log(instruction);
// TODO finalize play button behavior
// TODO add tabs for best/worst cases
// TODO add links to stats
// TODO fade unfade
// TODO heap sort
// TODO extra memory
// NOTE interesting (anti?)pattern here.
// NOTE use of call() vs apply() (apply only delivered first array item as string)
if (typeof operation === 'function') {
operation.call(this, instruction);
// if (typeof operation === 'function') {
// operation.call(this, instruction);
if (delay === 0) {
this.instructionIndex++;
this.followInstruction();
}
else if (this.paused === false) {
this.instructionIndex++;
setTimeout(this.followInstruction.bind(this), delay);
}
instruction[0].apply(this, args);
if (delay === 0) {
this.instructionIndex++;
this.followInstruction();
}
else {
console.error(i);
throw new Error('Unidentified instruction.');
else if (this.paused === false) {
this.instructionIndex++;
setTimeout(this.followInstruction.bind(this), delay);
}
// }
// else {
// console.error(i);
// throw new Error('Unidentified instruction.');
// }
};

Loading…
Cancel
Save