291 lines
6.1 KiB
HTML
291 lines
6.1 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<script>
|
|
"use strict";
|
|
var TIMEOUT = 16;
|
|
var EL_COUNT = 100;
|
|
|
|
window.onload = function() {
|
|
display.build(EL_COUNT, document.body);
|
|
};
|
|
|
|
//
|
|
// Infrastructure
|
|
//
|
|
|
|
var display = {
|
|
highlighted: false,
|
|
build: function(size, parent_id) {
|
|
var parent = document.getElementById(parent_id);
|
|
parent.style.position = 'relative';
|
|
parent.style.display = 'block';
|
|
parent.style.width = (10 * size)+'px';
|
|
parent.style.height = (3 * size)+'px';
|
|
|
|
for (var i = 0; i < size; i++) {
|
|
var d = document.createElement('div');
|
|
d.style.position = 'absolute';
|
|
d.style.display = 'block';
|
|
d.style['background-color'] = 'green';
|
|
d.style.width = '10px';
|
|
|
|
d.style.left = (10 * i)+'px';
|
|
d.id = 'el-'+i;
|
|
parent.appendChild(d);
|
|
|
|
this.set(i, i);
|
|
}
|
|
EL_COUNT = size;
|
|
this.clear_highlight();
|
|
},
|
|
set: function(idx, val) {
|
|
var el = document.getElementById('el-'+idx);
|
|
if (! el) {
|
|
console.log("Invalid set " + idx);
|
|
return;
|
|
}
|
|
el.style.height = (val * 3) + 'px';
|
|
el.style.top = ((EL_COUNT - val) * 3) + 'px';
|
|
this.highlight(idx);
|
|
},
|
|
get: function(idx) {
|
|
var el = document.getElementById('el-'+idx);
|
|
if (! el) {
|
|
console.log("Invalid read "+idx);
|
|
return;
|
|
}
|
|
return parseInt(el.style.height) / 3;
|
|
},
|
|
swap: function(a, b) {
|
|
var tmp = this.get(a);
|
|
this.set(a, this.get(b));
|
|
this.set(b, tmp);
|
|
},
|
|
reset: function() {
|
|
for (var i = 0; i < EL_COUNT; i++) this.set(i, i);
|
|
this.clear_highlight();
|
|
},
|
|
highlight: function(idx) {
|
|
this.clear_highlight();
|
|
document.getElementById('el-'+idx).
|
|
style['background-color'] = 'darkgreen';
|
|
this.highlighted = idx;
|
|
},
|
|
clear_highlight: function(idx) {
|
|
if (this.highlighted === false) return;
|
|
document.getElementById('el-'+this.highlighted).
|
|
style['background-color'] = 'green';
|
|
this.highlighted = false;
|
|
}
|
|
};
|
|
|
|
var Set = function() {
|
|
this.moves = [];
|
|
this.items = [];
|
|
|
|
for (var i = 0; i < EL_COUNT; i++) {
|
|
this.items.push( display.get(i) );
|
|
}
|
|
};
|
|
|
|
Set.prototype.get = function(idx) {
|
|
return this.items[idx];
|
|
}
|
|
Set.prototype.swap = function(a, b) {
|
|
this.moves.push([a, b]);
|
|
var tmp = this.items[a];
|
|
this.items[a] = this.items[b];
|
|
this.items[b] = tmp;
|
|
}
|
|
Set.prototype.apply = function() {
|
|
for (var i = 0, e = this.moves.length; i < e; i++) {
|
|
display.swap(this.moves[i][0], this.moves[i][1]);
|
|
}
|
|
this.moves = [];
|
|
display.clear_highlight();
|
|
}
|
|
Set.prototype.animate = function() {
|
|
if (this.moves.length) {
|
|
display.swap(this.moves[0][0], this.moves[0][1]);
|
|
this.moves = this.moves.slice(1);
|
|
setTimeout(this.animate.bind(this), TIMEOUT);
|
|
} else {
|
|
display.clear_highlight();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Sorts
|
|
//
|
|
|
|
var doPermute = function() {
|
|
var s = new Set();
|
|
for (var i = 0; i < EL_COUNT; i++) {
|
|
s.swap(Math.floor(Math.random()*EL_COUNT), i);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
var doPerturb = function() {
|
|
var s = new Set();
|
|
for (var i = 5; i < EL_COUNT - 5; i++) {
|
|
s.swap(i, Math.floor(Math.random()*10)+i-5);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
var doReverse = function() {
|
|
var s = new Set();
|
|
for (var i = 0; i < EL_COUNT/2; i++) {
|
|
s.swap(i, EL_COUNT-i-1);
|
|
}
|
|
return s;
|
|
}
|
|
|
|
var doBubble = function() {
|
|
// Outline: Wikipedia
|
|
|
|
var s = new Set();
|
|
|
|
var n = EL_COUNT;
|
|
do {
|
|
var new_n = 0;
|
|
for (var i = 1; i < n; i++) {
|
|
if (s.get(i-1) > s.get(i)) {
|
|
s.swap(i-1, i);
|
|
new_n = i;
|
|
}
|
|
}
|
|
n = new_n;
|
|
} while(n);
|
|
|
|
return s;
|
|
}
|
|
|
|
var doQuick = function() {
|
|
// Outline: Wikipedia
|
|
|
|
var partition = function(set, left, right, pivot) {
|
|
var pval = set.get(pivot);
|
|
set.swap(pivot, right);
|
|
var store_idx = left;
|
|
for (var i = left; i < right; i++) {
|
|
if (set.get(i) < pval) {
|
|
set.swap(i, store_idx);
|
|
store_idx++;
|
|
}
|
|
}
|
|
set.swap(store_idx, right);
|
|
return store_idx;
|
|
};
|
|
|
|
var qsort = function(set, left, right) {
|
|
if (left < right) {
|
|
var pivot_idx = Math.floor((right - left)/2) + left;
|
|
|
|
var pivot_new = partition(set, left, right, pivot_idx);
|
|
qsort(set, left, pivot_new-1);
|
|
qsort(set, pivot_new+1, right);
|
|
}
|
|
};
|
|
|
|
var s = new Set();
|
|
qsort(s, 0, s.items.length - 1);
|
|
return s;
|
|
}
|
|
|
|
var doHeap = function() {
|
|
// Outline: Wikipedia
|
|
|
|
var heapify = function(s, count) {
|
|
var start = (count-2) / 2;
|
|
while (start >= 0) {
|
|
siftdown(s, start, count-1);
|
|
start--;
|
|
}
|
|
};
|
|
|
|
var siftdown = function(s, start, end) {
|
|
var root = start;
|
|
while (root*2 < end) {
|
|
var child = root*2 + 1;
|
|
var swap = root;
|
|
if (s.get(swap) < s.get(child)) {
|
|
swap = child;
|
|
}
|
|
if (child+1 <= end && s.get(swap) < s.get(child+1)) {
|
|
swap = child + 1;
|
|
}
|
|
if (swap != root) {
|
|
s.swap(root, swap);
|
|
root = swap;
|
|
} else {
|
|
return;
|
|
}
|
|
};
|
|
};
|
|
|
|
var s = new Set();
|
|
heapify(s, s.items.length);
|
|
var end = s.items.length - 1;
|
|
while (end) {
|
|
s.swap(end, 0);
|
|
end--;
|
|
siftdown(s, 0, end);
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
var doMerge = function() {
|
|
// Outline: http://www.cs.ubc.ca/~harrison/Java/MergeSortAlgorithm.java.html
|
|
|
|
var msort = function(s, lo, hi) {
|
|
if (lo >= hi) return;
|
|
var mid = Math.floor((lo + hi) / 2);
|
|
|
|
msort(s, lo, mid);
|
|
msort(s, mid+1, hi);
|
|
|
|
var end_lo = mid;
|
|
var start_hi = mid+1;
|
|
while ((lo <= end_lo) && (start_hi <= hi)) {
|
|
if (s.get(lo) < s.get(start_hi)) {
|
|
lo++;
|
|
} else {
|
|
for (var k = start_hi - 1; k >= lo; k--) {
|
|
s.swap(k+1, k);
|
|
}
|
|
end_lo++;
|
|
start_hi++;
|
|
}
|
|
}
|
|
}
|
|
|
|
var s = new Set();
|
|
msort(s, 0, s.items.length - 1);
|
|
return s;
|
|
}
|
|
|
|
|
|
|
|
</script>
|
|
<title>sorts</title>
|
|
</head>
|
|
<body onload="display.build(100, 'area');">
|
|
<div id="area"></div>
|
|
<a href="javascript:display.reset()">reset</a>
|
|
|
|
|
<a href="javascript:doPermute().animate()">permute</a>
|
|
<a href="javascript:doPerturb().animate()">perturb</a>
|
|
<a href="javascript:doReverse().animate()">reverse</a>
|
|
|
|
|
<a href="javascript:doBubble().animate()">bubble</a>
|
|
<a href="javascript:doQuick().animate()">quick</a>
|
|
<a href="javascript:doHeap().animate()">heap</a>
|
|
<a href="javascript:doMerge().animate()">merge</a>
|
|
</body>
|
|
</html>
|