blob: 4714b9cc3985f6fe68e59dbb71ef96ce0a854d0f [file] [log] [blame]
"use strict";
function TEST_mergeSort()
{
function createRNG(seed)
{
return function() {
// Robert Jenkins' 32 bit integer hash function.
seed = ((seed + 0x7ed55d16) + (seed << 12)) & 0xffffffff;
seed = ((seed ^ 0xc761c23c) ^ (seed >>> 19)) & 0xffffffff;
seed = ((seed + 0x165667b1) + (seed << 5)) & 0xffffffff;
seed = ((seed + 0xd3a2646c) ^ (seed << 9)) & 0xffffffff;
seed = ((seed + 0xfd7046c5) + (seed << 3)) & 0xffffffff;
seed = ((seed ^ 0xb55a4f09) ^ (seed >>> 16)) & 0xffffffff;
return (seed & 0xfffffff) / 0x10000000;
};
}
let random = createRNG(0x7a11bec8);
function mergeSorted(array, compare)
{
if (array.length <= 1)
return array;
let midIndex = Math.floor(array.length / 2);
let left = mergeSorted(array.slice(0, midIndex), compare);
let right = mergeSorted(array.slice(midIndex), compare);
let result = [];
function finish(source, index)
{
if (index >= source.length)
return;
result.push(source[index]);
return finish(source, index + 1);
}
function merge(leftIndex, rightIndex)
{
if (leftIndex >= left.length)
return finish(right, rightIndex);
if (rightIndex >= right.length)
return finish(left, leftIndex);
let leftValue = left[leftIndex];
let rightValue = right[rightIndex];
let comparisonResult = compare(leftValue, rightValue);
if (comparisonResult < 0) {
result.push(leftValue);
return merge(leftIndex + 1, rightIndex);
}
result.push(rightValue);
return merge(leftIndex, rightIndex + 1);
}
merge(0, 0);
return result;
}
function checkSorted(array)
{
function check(index)
{
if (index >= array.length - 1)
return;
if (array[index] > array[index + 1])
throw new Error("array not sorted at index " + index + ": " + array);
return check(index + 1);
}
check(0);
}
function checkSpectrum(a, b)
{
var aMap = new Map();
var bMap = new Map();
function add(map, value)
{
let existing = map.get(value);
if (existing == null)
existing = 0;
map.set(value, existing + 1);
}
function build(map, array, index)
{
if (index >= array.length)
return;
add(map, array[index]);
return build(map, array, index + 1);
}
build(aMap, a, 0);
build(bMap, b, 0);
function compare(keys)
{
let entry = keys.next();
if (entry.done)
return;
if (aMap.get(entry.value) != bMap.get(entry.value))
throw new Error("arrays don't have the same number of: " + entry.value + " (a = " + a + ", b = " + b + ")");
return compare(keys);
}
compare(aMap.keys());
}
function buildArray(length, value)
{
let array = [];
function build()
{
if (array.length >= length)
return;
array.push(value(array.length));
return build();
}
build();
return array;
}
let arrays = [
buildArray(10, x => x),
buildArray(10, x => -x),
buildArray(10000, x => random())
];
function test(index)
{
if (index >= arrays.length)
return;
let array = arrays[index];
let sorted = mergeSorted(array, (a, b) => a < b ? -1 : a > b ? 1 : 0);
checkSorted(sorted);
checkSpectrum(array, sorted);
test(index + 1)
}
test(0);
}
for (var i = 0; i < 100; ++i)
TEST_mergeSort();