【发布时间】:2015-04-07 21:16:03
【问题描述】:
我得到了算法的两种实现:一种是shell排序,另一种是归并排序。 Shell 排序复杂度接近 n^1.5,合并排序为 n * logn,因此基本上合并排序应该更快。但是,在我的测试中,我看到了不同的结果:shell 排序比合并排序快得多。我相信我做错了什么,但没有看到这一点。
Shell 排序实现:
var shell_sort = function(array){
var length = array.length;
var h = 1;
while( h < length / 3){
h = 3 * h + 1;
}
while( h > 0 ){
for ( var i = h; i < length; i++){
for ( var j = i; j > 0 && array[j] < array[j-h]; j-=h){
array.swap(j, j-h);
}
}
//decreasing h
h = --h / 3
}
return array;
};
合并排序:
var merge_sort = function(array){
function merge(left, right){
var result = [];
var il = 0;
var ir = 0;
while (il < left.length && ir < right.length){
if (left[il] < right[ir]){
result.push(left[il++]);
} else {
result.push(right[ir++]);
}
}
if ( il < left.length){
result.push.apply(result,left.slice(il));
}
if (ir < right.length){
result.push.apply(result,right.slice(ir));
}
return result;
}
function merge_sort(items){
//well it is only 1 element
if (items.length < 2){
return items;
}
var middle = Math.floor(items.length / 2);
//create two arrays
var left = items.slice(0, middle);
var right = items.slice(middle);
return merge(merge_sort(left), merge_sort(right));
}
return merge_sort(array);
};
1000 万个元素的数组的结果基本上是下一个:
Shell 排序:12725ms
合并排序:34338ms
测试很简单:
//sorting 100000 elements
array.generate_numbers(10000000);
console.time('10000000elements');
sort_algs(array);
console.timeEnd('10000000elements');
其中 generate_numbers 是一个简单的辅助函数,它生成具有配置大小的数字数组,而 swap 是一个改变元素位置的函数。
【问题讨论】:
-
当在 V8 等现代内核上运行时,您根本无法指望 CS101 为编译代码做出的性能估计,因为它有自己的一组优化和瓶颈。简而言之,可能是对象访问或 [].slice() 与 [].push() 的性能比实际算法的时间更长;谁知道...无论如何,您应该使用内置的 [].sort() 以获得最佳性能。
-
我虽然这样 :) 但真的很感兴趣是什么让这项工作如此缓慢:)
-
您可以将计时器插入代码本身以跟踪性能,尽管您需要逐步执行更小的数组来执行此操作...查看代码,您的合并排序似乎需要一堆新数组,每个数组都在自己的范围内,而第一个数组则将它们全部保存在一个范围内,这样可以节省大量拆解并提供更多优化机会。
-
“所以基本上合并排序应该更快”只有当你选择 n 足够大时,显然你没有
标签: javascript arrays algorithm