125 lines
2.9 KiB
JavaScript
125 lines
2.9 KiB
JavaScript
|
|
function swap(arr, a, b) {
|
||
|
|
var tmp = arr[a];
|
||
|
|
arr[a] = arr[b];
|
||
|
|
arr[b] = tmp;
|
||
|
|
}
|
||
|
|
|
||
|
|
function partition(arr, pivot, left, right, compare) {
|
||
|
|
var storeIndex = left;
|
||
|
|
var pivotValue = arr[pivot]; // put the pivot on the right
|
||
|
|
|
||
|
|
swap(arr, pivot, right); // go through the rest
|
||
|
|
|
||
|
|
for (var v = left; v < right; v++) {
|
||
|
|
if (compare(arr[v], pivotValue) < 0) {
|
||
|
|
swap(arr, v, storeIndex);
|
||
|
|
storeIndex++;
|
||
|
|
}
|
||
|
|
} // finally put the pivot in the correct place
|
||
|
|
|
||
|
|
|
||
|
|
swap(arr, right, storeIndex);
|
||
|
|
return storeIndex;
|
||
|
|
}
|
||
|
|
|
||
|
|
function quickSort(array, compare, left, right) {
|
||
|
|
if (left < right) {
|
||
|
|
var pivot = Math.floor((left + right) / 2);
|
||
|
|
var newPivot = partition(array, pivot, left, right, compare);
|
||
|
|
quickSort(array, compare, left, newPivot - 1);
|
||
|
|
quickSort(array, compare, newPivot + 1, right);
|
||
|
|
}
|
||
|
|
} // TODO Test.
|
||
|
|
|
||
|
|
|
||
|
|
function ProgressiveQuickSort() {
|
||
|
|
// this._pivotList = new LinkedList();
|
||
|
|
this._parts = [];
|
||
|
|
}
|
||
|
|
|
||
|
|
ProgressiveQuickSort.prototype.step = function (arr, compare, frame) {
|
||
|
|
var len = arr.length;
|
||
|
|
|
||
|
|
if (frame === 0) {
|
||
|
|
this._parts = [];
|
||
|
|
this._sorted = false; // Pick a start pivot;
|
||
|
|
|
||
|
|
var pivot = Math.floor(len / 2);
|
||
|
|
|
||
|
|
this._parts.push({
|
||
|
|
pivot: pivot,
|
||
|
|
left: 0,
|
||
|
|
right: len - 1
|
||
|
|
});
|
||
|
|
|
||
|
|
this._currentSortPartIdx = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (this._sorted) {
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
var parts = this._parts;
|
||
|
|
|
||
|
|
if (parts.length === 0) {
|
||
|
|
this._sorted = true; // Already finished.
|
||
|
|
|
||
|
|
return true;
|
||
|
|
} else if (parts.length < 512) {
|
||
|
|
// Sort large parts in about 10 frames.
|
||
|
|
for (var i = 0; i < parts.length; i++) {
|
||
|
|
// Partition and Modify the pivot index.
|
||
|
|
parts[i].pivot = partition(arr, parts[i].pivot, parts[i].left, parts[i].right, compare);
|
||
|
|
}
|
||
|
|
|
||
|
|
var subdividedParts = [];
|
||
|
|
|
||
|
|
for (var i = 0; i < parts.length; i++) {
|
||
|
|
// Subdivide left
|
||
|
|
var left = parts[i].left;
|
||
|
|
var right = parts[i].pivot - 1;
|
||
|
|
|
||
|
|
if (right > left) {
|
||
|
|
subdividedParts.push({
|
||
|
|
pivot: Math.floor((right + left) / 2),
|
||
|
|
left: left,
|
||
|
|
right: right
|
||
|
|
});
|
||
|
|
} // Subdivide right
|
||
|
|
|
||
|
|
|
||
|
|
var left = parts[i].pivot + 1;
|
||
|
|
var right = parts[i].right;
|
||
|
|
|
||
|
|
if (right > left) {
|
||
|
|
subdividedParts.push({
|
||
|
|
pivot: Math.floor((right + left) / 2),
|
||
|
|
left: left,
|
||
|
|
right: right
|
||
|
|
});
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
parts = this._parts = subdividedParts;
|
||
|
|
} else {
|
||
|
|
// console.time('sort');
|
||
|
|
// Finally quick sort each parts in 10 frames.
|
||
|
|
for (var i = 0; i < Math.floor(parts.length / 10); i++) {
|
||
|
|
// Sort near parts first.
|
||
|
|
var idx = parts.length - 1 - this._currentSortPartIdx;
|
||
|
|
quickSort(arr, compare, parts[idx].left, parts[idx].right);
|
||
|
|
this._currentSortPartIdx++; // Finish sort
|
||
|
|
|
||
|
|
if (this._currentSortPartIdx === parts.length) {
|
||
|
|
this._sorted = true;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
} // console.timeEnd('sort');
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
};
|
||
|
|
|
||
|
|
ProgressiveQuickSort.sort = quickSort;
|
||
|
|
export default ProgressiveQuickSort;
|