【发布时间】:2016-11-21 13:48:53
【问题描述】:
在我的应用程序中,我需要对随机数的大型数组(介于 100,000 和 1,000,000 之间)进行排序。
我一直在使用内置的 array.sort(comparisonFunction),其中的 compareFunction 如下所示:
function comparisonFunction(a,b) {
return a-b;
}
这很好用,但我读过(例如,Native JavaScript sort performing slower than implemented mergesort and quicksort)有更快的选择,特别是如果您的要求满足某些条件:
- 我只需要对数字进行排序(例如,不是对象或字母数字数据)
- 数据是随机的(不可能已经排序)
- 排序不需要稳定
那么 - 在这些情况下可用的最快(或足够接近)的排序算法是什么?
还有,是否有规范的(或至少相对理想的)JavaScript 实现?
[更新]
所以,快速澄清一下 - 在链接的问题中,OP 需要一个稳定的排序。因为我没有 - 我想知道这是否会改变答案(即,如果您事先知道您的数据不会被预先排序,那么也许有一个更快的排序选项可用 '不需要稳定的排序)。
也许答案是“不”,但这就是我要问的原因。
[更新 #2]
这是一个快速排序的实现,除非我犯了错误 - 轻松击败本机排序功能:
function comparisonFunction(a, b) {
return a - b;
}
function quickSort(arr, leftPos, rightPos, arrLength) {
let initialLeftPos = leftPos;
let initialRightPos = rightPos;
let direction = true;
let pivot = rightPos;
while ((leftPos - rightPos) < 0) {
if (direction) {
if (arr[pivot] < arr[leftPos]) {
quickSort.swap(arr, pivot, leftPos);
pivot = leftPos;
rightPos--;
direction = !direction;
} else
leftPos++;
} else {
if (arr[pivot] <= arr[rightPos]) {
rightPos--;
} else {
quickSort.swap(arr, pivot, rightPos);
leftPos++;
pivot = rightPos;
direction = !direction;
}
}
}
if (pivot - 1 > initialLeftPos) {
quickSort(arr, initialLeftPos, pivot - 1, arrLength);
}
if (pivot + 1 < initialRightPos) {
quickSort(arr, pivot + 1, initialRightPos, arrLength);
}
}
quickSort.swap = (arr, el1, el2) => {
let swapedElem = arr[el1];
arr[el1] = arr[el2];
arr[el2] = swapedElem;
}
var
i,
arr1, arr2,
length;
length = 1000000;
arr1 = [];
arr2 = [];
for (i = 0; i < length; i++) {
arr1.push(Math.random());
arr2.push(Math.random());
}
console.time("nativeSort");
arr1.sort(comparisonFunction);
console.timeEnd("nativeSort");
console.time("quickSort");
quickSort(arr2, 0, length - 1, length);
console.timeEnd("quickSort");
【问题讨论】:
-
"...我听说有更快的选择..."在哪里?
-
请注意,原生 JavaScript
.sort()不需要稳定。如果对于任何显着大小的数组,JavaScript 排序比本机排序更快,我会感到惊讶,尽管在某些输入约束下,基数排序可能值得一试。 -
@Liam:除了上面清楚地说明它不需要需要一个稳定的排序。 (请注意,如果您要对数字进行排序,稳定与不稳定是没有区别的区别......)
-
@mattstuehler - 我可以发布一个快速排序的 C++ 示例,随着重复次数的增加,它最终运行得更快。在进行类似 Hoare 的分区后,有两个 2 行循环用于排除所有中间值 == 枢轴值。在平均情况下几乎没有影响,如果所有值都相同,则运行时间为 O(n)。您可以轻松修改现有的 javascript 快速排序或 introsort 以遵循相同的逻辑。
-
您的快速排序实现存在缺陷。如果输入数组中有太多重复项,例如用 1-100 之间的随机整数填充 1M 大小的输入数组,则会出现调用堆栈溢出(超出最大调用堆栈错误)。我建议您切换到 while 循环而不是递归调用。或者..我会说实现尾调用优化的递归函数,唉,截至今天,TCO 在 JS 引擎中是个笑话。它根本不起作用。
标签: javascript arrays sorting