Javascript 为什么要使用<;对JS数字数组进行排序;工作

Javascript 为什么要使用<;对JS数字数组进行排序;工作,javascript,Javascript,在JavaScript中对数字数组进行排序时,我意外地使用了,具体取决于sort()实现,很可能它从未检查-1。它更简单、更快,而且没有任何区别(因为无论如何,分类都不能保证是稳定的,IIRC) 如果内部执行的检查sort()为compareFunction(a,b)>0,则实际上true被解释为a>b,false被解释为a比较true覆盖为1,而false覆盖为0 注意:这都是猜测和猜测,我还没有通过实验或在浏览器源代码中证实这一点,但它很可能是正确的。如果我们分析所做的事情,这似乎大部分是运

在JavaScript中对数字数组进行排序时,我意外地使用了
,具体取决于
sort()
实现,很可能它从未检查
-1
。它更简单、更快,而且没有任何区别(因为无论如何,分类都不能保证是稳定的,IIRC)

如果内部执行的检查
sort()
compareFunction(a,b)>0
,则实际上
true
被解释为
a>b
false
被解释为
a
比较
true
覆盖为1,而
false
覆盖为0


注意:这都是猜测和猜测,我还没有通过实验或在浏览器源代码中证实这一点,但它很可能是正确的。

如果我们分析所做的事情,这似乎大部分是运气,因为在这种情况下,3和2被认为是“相同”的,应该是可互换的。我假设在这种情况下,JS引擎对任何被认为相等的值都保持原始顺序:

设a=[1,3,2,4];
a、 排序((n1,n2)=>{
常数结果=n10){
log(${n2}在${n1}之前);
}否则{
log(${n1}与${n2}位于同一位置);
}
返回结果;
})

控制台日志(a)
由于其较小的尺寸以及Chrome V8(可能还有其他浏览器)中当前实现的
排序,这种排序可以在您的输入阵列上工作

比较器函数的返回值定义在:

  • 如果
    compareFunction(a,b)
    小于0,则将
    a
    排序为小于0的索引
    b
    ,即
    a
    排在第一位
  • 如果
    compareFunction(a,b)
    返回0,则保留
    a
    b
    彼此之间没有变化,但对所有对象进行排序 不同的元素
  • 如果
    compareFunction(a,b)
    大于0,则将
    b
    排序到低于
    a
    的索引,即
    b
    排在第一位
但是,您的函数返回二进制
true
false
,与数字相比,其计算结果分别为
1
0
。这有效地将
n1
中的比较与
n1===n2
合并,声称两者是相等的。如果
n1
为9且
n2
为3,
9<3==false
0
。换句话说,排序时9和3“彼此保持不变”,而不是坚持“将9排序到低于3的索引”

如果您的数组小于11个元素,则Chrome V8的排序例程将显示为,并且不执行任何步骤:

但是,在选择轴心点和分区时,依赖于所有三种比较:

var order = comparefn(element, pivot);
if (order < 0) {
  // ...
} else if (order > 0) {
  // ...
}
// move on to the next iteration of the partition loop
var order=comparefn(元素,轴);
如果(顺序<0){
// ...
}否则,如果(订单>0){
// ...
}
//继续进行分区循环的下一次迭代
这保证了对数组(如
[1,3,2,4]
)的准确排序,并至少会将包含10个以上元素的数组置于一个几乎肯定不准确的快速排序步骤中


更新7/19/19:由于在本回答中讨论了V8(6)的版本,V8的数组排序的实现移到了7.0中,如本文所讨论的,插入排序在的数组上调用

上面链接的文章描述了问题发生时V8排序的历史情况:

Array.prototype.sort
TypedArray.prototype.sort
依赖于用JavaScript编写的相同快速排序实现。排序算法本身相当简单:其基础是快速排序,对于较短的数组(长度<10),插入排序可回退。当快速排序递归达到子数组长度10时,也会使用插入排序回退。对于较小的数组,插入排序更有效。这是因为快速排序在分区后会被递归调用两次。每个递归调用都有创建(和丢弃)堆栈帧的开销

无论实现细节有何变化,如果排序比较器遵守标准,代码将按预期排序,但如果比较器未履行合同,则所有赌注都将取消。

需要一个返回数字(负、零或正)的比较器

假设您在V8引擎(Node.js、Chrome等)上运行,您会发现返回值与0比较(
yourrurnvalue>0
)。在这种情况下,返回值被转换为一个数字,因此:

  • Truthy值转换为1
  • Falsy值将转换为0

因此,基于文档和上述内容,您的函数将在特定情况下以降序返回排序数组,但在其他情况下可能会停止,因为不考虑-1值。

在我最初的评论之后,我想知道查找此排序方法失败的数组有多容易

我对长度不超过8的数组(在数组大小的字母表上)进行了彻底的搜索,但没有找到任何结果。由于我的算法开始太慢了,我把它改成了大小为2的字母表,发现长度为10的二进制数组都能正确排序。但是,对于长度为11的二进制数组,许多数组的排序不正确,例如
[0,1,1,1,1,1,1,1,0]

// Check if 'array' is properly sorted using the "<" comparator function
function sortWorks(array) {
    let sorted_array = array.sort(function(n1, n2) {
        return n1 < n2;
    });
    for (let i=0; i<sorted_array.length-1; i++) {
        if (sorted_array[i] < sorted_array[i+1]) return false;
    }
    return true;
}

// Get a list of all arrays of length 'count' on an alphabet of size 'max_n'.
// I know it's awful, don't yell at me :'(
var arraysGenerator;
arraysGenerator = function (max_n, count) {
    if (count === 0) return [[]];
    let arrays = arraysGenerator(max_n, count-1);
    let result = [];
    for (let array of arrays) {
        for (let i = 0; i<max_n; i++) {
            result.push([i].concat(array));
        }
    }
    return result;
}

// Check if there are binary arrays of size k which are improperly sorted,
// and if so, log them
function testArraysOfSize(k) {
    let arrays = arraysGenerator(2, k);
    for (let array of arrays) {
        if (!sortWorks(array)) {
            console.log(array);
        }
    }
}

//使用“您可以通过查看返回值的数值来检查数组”是否正确排序。注意返回值
0
具有跨浏览器含义。@usr2564301
return n2-n1
一个不起作用的示例的可能重复项是
[1,2,1,2,1,2,1,2,1,2]
。我不知道简短的示例是否会失败。@Nic
// Insertion sort is faster for short arrays.
if (to - from <= 10) {
  InsertionSort(a, from, to);
  return;
}
var order = comparefn(tmp, element);
if (order > 0) {
  a[j + 1] = tmp;
} else {
  break;
}
var order = comparefn(element, pivot);
if (order < 0) {
  // ...
} else if (order > 0) {
  // ...
}
// move on to the next iteration of the partition loop
// Check if 'array' is properly sorted using the "<" comparator function
function sortWorks(array) {
    let sorted_array = array.sort(function(n1, n2) {
        return n1 < n2;
    });
    for (let i=0; i<sorted_array.length-1; i++) {
        if (sorted_array[i] < sorted_array[i+1]) return false;
    }
    return true;
}

// Get a list of all arrays of length 'count' on an alphabet of size 'max_n'.
// I know it's awful, don't yell at me :'(
var arraysGenerator;
arraysGenerator = function (max_n, count) {
    if (count === 0) return [[]];
    let arrays = arraysGenerator(max_n, count-1);
    let result = [];
    for (let array of arrays) {
        for (let i = 0; i<max_n; i++) {
            result.push([i].concat(array));
        }
    }
    return result;
}

// Check if there are binary arrays of size k which are improperly sorted,
// and if so, log them
function testArraysOfSize(k) {
    let arrays = arraysGenerator(2, k);
    for (let array of arrays) {
        if (!sortWorks(array)) {
            console.log(array);
        }
    }
}