mirror of
https://github.com/mourner/flatbush.git
synced 2026-01-25 14:08:13 +00:00
Switch to non recursive quicksort (#70)
* added test * add Bentley-McIlroy 3-way partitioning * switch to non recursive implementation * fixed stack handling * rename function * escaped ts errors + enhanced performance * remove escaped error * additional performance enhancement
This commit is contained in:
parent
1e333b0369
commit
34d7277eec
68
index.js
68
index.js
@ -349,12 +349,58 @@ function upperBound(value, arr) {
|
||||
* @param {number} nodeSize
|
||||
*/
|
||||
function sort(values, boxes, indices, left, right, nodeSize) {
|
||||
if (Math.floor(left / nodeSize) >= Math.floor(right / nodeSize)) return;
|
||||
const stack = [];
|
||||
let stackPointer = 0;
|
||||
|
||||
stack.push(left);
|
||||
stackPointer++;
|
||||
stack.push(right);
|
||||
stackPointer++;
|
||||
|
||||
while (stackPointer > 0) {
|
||||
// @ts-expect-error
|
||||
const r = stack.pop();
|
||||
stackPointer--;
|
||||
const l = stack.pop();
|
||||
stackPointer--;
|
||||
|
||||
// @ts-expect-error
|
||||
if ((r - l) <= nodeSize) {
|
||||
// @ts-expect-error
|
||||
if (Math.floor(l / nodeSize) >= Math.floor(r / nodeSize)) continue;
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
const pivot = getPivot(values, l, r);
|
||||
|
||||
// @ts-expect-error
|
||||
let i = l - 1;
|
||||
// @ts-expect-error
|
||||
let j = r + 1;
|
||||
|
||||
while (true) {
|
||||
do i++; while (values[i] < pivot);
|
||||
do j--; while (values[j] > pivot);
|
||||
if (i >= j) break;
|
||||
swap(values, boxes, indices, i, j);
|
||||
}
|
||||
|
||||
stack.push(l, j, j + 1, r);
|
||||
stackPointer += 4;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine pivot value.
|
||||
* @param {Uint32Array} values
|
||||
* @param {number} l
|
||||
* @param {number} r
|
||||
*/
|
||||
function getPivot(values, l, r) {
|
||||
// apply median of three method
|
||||
const start = values[left];
|
||||
const mid = values[(left + right) >> 1];
|
||||
const end = values[right];
|
||||
const start = values[l];
|
||||
const mid = values[(l + r) >> 1];
|
||||
const end = values[r];
|
||||
|
||||
let pivot = end;
|
||||
|
||||
@ -366,19 +412,7 @@ function sort(values, boxes, indices, left, right, nodeSize) {
|
||||
} else if (x === mid) {
|
||||
pivot = Math.max(start, end);
|
||||
}
|
||||
|
||||
let i = left - 1;
|
||||
let j = right + 1;
|
||||
|
||||
while (true) {
|
||||
do i++; while (values[i] < pivot);
|
||||
do j--; while (values[j] > pivot);
|
||||
if (i >= j) break;
|
||||
swap(values, boxes, indices, i, j);
|
||||
}
|
||||
|
||||
sort(values, boxes, indices, left, j, nodeSize);
|
||||
sort(values, boxes, indices, j + 1, right, nodeSize);
|
||||
return pivot;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
31
test.js
31
test.js
@ -250,4 +250,35 @@ test('quicksort should work with an inbalanced dataset', () => {
|
||||
});
|
||||
});
|
||||
|
||||
test('quicksort should work with duplicates', () => {
|
||||
const n = 55000 + 5500 + 7700;
|
||||
const index = new Flatbush(n);
|
||||
|
||||
let x = 0;
|
||||
|
||||
for (let p = 0; p < 55000; p++) {
|
||||
index.add(x, 3.0, x, 3.0);
|
||||
x++;
|
||||
}
|
||||
|
||||
for (let p = 0; p < 5500; p++) {
|
||||
index.add(x, 4.0, x, 4.0);
|
||||
x++;
|
||||
}
|
||||
|
||||
for (let p = 0; p < 7700; p++) {
|
||||
index.add(x, 5.0, x, 5.0);
|
||||
x++;
|
||||
}
|
||||
|
||||
index.finish();
|
||||
|
||||
assert.doesNotThrow(() => {
|
||||
index.search(0.5, -1, 6.5, 1);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
function compare(a, b) { return a - b; }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user