Fix stack overflow for some degenerate data cases (#65)

* fix pivot selection

* add regression test

* fix linting
This commit is contained in:
muendlein 2025-05-18 22:37:55 +02:00 committed by GitHub
parent 3a6f0f0cc5
commit 1e87f4071d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 44 additions and 1 deletions

View File

@ -343,7 +343,22 @@ function upperBound(value, arr) {
function sort(values, boxes, indices, left, right, nodeSize) {
if (Math.floor(left / nodeSize) >= Math.floor(right / nodeSize)) return;
const pivot = values[(left + right) >> 1];
// apply median of three method
const start = values[left];
const mid = values[(left + right) >> 1];
const end = values[right];
let pivot = end;
const x = Math.max(start, mid);
if (end > x) {
pivot = x;
} else if (x === start) {
pivot = Math.max(mid, end);
} else if (x === mid) {
pivot = Math.max(start, end);
}
let i = left - 1;
let j = right + 1;

28
test.js
View File

@ -222,4 +222,32 @@ test('reconstructs an index from SharedArrayBuffer', () => {
assert.deepEqual(index, index2);
});
test('quicksort should work with an inbalanced dataset', () => {
const n = 15000;
const index = new Flatbush(2 * n);
function linspace(start, stop, num, endpoint = true) {
const div = endpoint ? (num - 1) : num;
const step = (stop - start) / div;
return Array.from({length: num}, (_, i) => start + step * i);
}
const items = linspace(0, 1000, n);
const items2 = linspace(0, 1000, n);
for (const p of items) {
index.add(p, 0, p, 0);
}
for (const p of items2) {
index.add(p, 0, p, 0);
}
index.finish();
assert.doesNotThrow(() => {
index.search(-100, -1, 15000, 1);
});
});
function compare(a, b) { return a - b; }