NodeJS 14.4.0对Array使用了什么排序算法?

9ceoxa92  于 12个月前  发布在  Node.js
关注(0)|答案(2)|浏览(173)

我不相信这是这个How does Javascript's sort() work?的复制品

let arr = [3, 4, 2, 1];
arr.sort((second,first) => {
  console.log([first, second]);
  if (first>second) {
    return -1; // switch them
  }
  return 0; // don't switch them

});
console.log(arr);

字符串
这将返回

[ 3, 4 ]
[ 4, 2 ]
[ 4, 2 ] <---- Why is this output twice?
[ 3, 2 ]
[ 3, 1 ]
[ 2, 1 ]
[ 1, 2, 3, 4 ]


我试图弄清楚NodeJS(14.4.0)对我的输入使用什么算法进行Array.sort?

7lrncoxx

7lrncoxx1#

在这个post中需要注意的是,v8引擎显然使用Timsort进行排序:
https://v8.dev/blog/array-sort#timsort

cunj1qz1

cunj1qz12#

正如@Joe所指出的,V8引擎已经用TimSort实现了Array.prototype.sort(),TimSort本身使用BinaryInsertionSort。我对V8 Torque语言了解不多,所以我实验的以下行为,我无法在链接的.tq文件中验证它。

let arr = [3, 4, 2, 1];
arr.sort((a, b) => {
  console.log(a, b);
  if (b > a) {
    return -1; // switch them
  }
  return 0; // don't switch them
});
console.log(arr);

字符串
是这样的:

// original array:
// 3 4 2 1
// insertion sort works by comparing items backyards
// so in the first iteration:
// (i = 1) a = 4
// (j = i - 1 = 0) b = 3
// console.log returns 4, 3
// your compareFn returns 0 in this case, so no swapping, elements are considered in order as per your compareFn
// you can notice that the input array will be mutated only at after the last iteration, but the implementation uses a copy internally to work with
// at the end of this first iteration, this internal array is still:
// 3 4 2 1
// next iteration (i++):
// (i = 2) a = 2
// (j = i - 1 = 1) b = 4
// console.log returns 2, 4
// now as per your compareFn, since it returns -1, both elements are considered not in order
// then something happens that I could not verify in the implementation: instead of decreasing j by 1 to find the index where `a` should be inserted like in the js example given [here][4], as soon as the first comparison fails (when a negative value is returned for the first time by the compareFn when comparing elements) the algorithm switches to a dichotomous logic on all the items in the internal array (sorted, then) before the current i index (representing the value `a` to reorder by insertion). So this includes element at current index j.
// next iteration (dichotomy starts):
// since there are 2 elements before `a`, it compares it with `b = 4` again)
// (i = 2) a = 2
// (j = 1) b = 4 (dichotomy logic: j = Math.ceil((i-1)/2)
// console.log returns 2, 4
// compareFn returns -1, so `b` and `a` not in order (already compared in this case but it is a trivial case where j points to the same element again by dichotomy because the original array is so small)
// next iteration:
// (i = 2) a = 2
// (j = 0) b = 3 (dichotomy logic again: j = prev_j - Math.ceil((i-1-prev_j)/2))
// console.log returns 2, 3
// compareFn returns -1, so still not in order
// j = 0 so all the elements before `a` are right shifted in the internal array and a is inserted at index 0:
// 2 3 4 1
// next iteration (i++):
// (i = 3) a = 1
// (j = 1) b = 3 (dichotomy logic: j = Math.ceil((i-1)/2)
// console.log returns 1, 3
// compareFn returns -1, so not in order
// next iteration:
// (i = 3) a = 1
// (j = 0) b = 2 (dichotomy logic again: j = prev_j - Math.ceil((i-1-prev_j)/2))
// console.log returns 1, 2
// compareFn returns -1, so not in order
// j = 0 so all the elements before `a` are right shifted in the internal array and a is inserted at index 0:
// 1 2 3 4
// done


如果你使用一个更大的数组,比如[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -1],你会更好地看到二分法逻辑:

-1 15
-1 8
-1 4
-1 2
-1 1
-1 0

相关问题