当前位置: 首页 > 知识库问答 >
问题:

为什么使用

解晟
2023-03-14

在JavaScript中对一组数字进行排序时,我不小心使用了< code >

例:

var a  = [1,3,2,4]
a.sort(function(n1, n2){
    return n1<n2
})
// result is correct: [4,3,2,1]

还有一个示例数组(感谢Nicolas的示例):

[1,2,1,2,1,2,1,2,1,2,1,2]

共有3个答案

商昂然
2023-03-14

如果我们分析正在做的事情,似乎这主要是运气,因为在这种情况下,3 和 2 被认为是“相同的”,应该是可以互换的。我想在这种情况下,JS 引擎会保留任何被视为相等的值的原始顺序:

let a = [1, 3, 2, 4];
a.sort((n1, n2) => {
  const result = n1 < n2;
  if (result < 0) {
    console.log(`${n1} comes before ${n2}`);
  } else if (result > 0) {
    console.log(`${n2} comes before ${n1}`);
  } else {
    console.log(`${n1} comes same position as ${n2}`);
  }
  return result;
})

console.log(a);
卢德惠
2023-03-14

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

我对长度不超过8的数组进行了彻底的搜索(在一个与数组大小相同的字母表上),但一无所获。由于我的(公认的低劣)算法开始太慢,我将它改为大小为2的字母表,并发现长度不超过10的二进制数组都可以正确排序。然而,对于长度为11的二进制数组,许多排序不正确,例如< code>[0,1,1,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);
        }
    }
}

但由于某种原因,我得到了一些奇怪的误报,不知道我的错误在哪里。

编辑:

检查了一会儿后,这里部分解释了为什么OP的“错误”排序方法适用于长度

来源:这里,感谢原作者。

山鸿彩
2023-03-14

这种排序在您的输入数组上有效,因为它的大小很小,而且当前在ChromeV8(可能还有其他浏览器)中实现了sort

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

  • 如果 compareFunction(a, b) 小于 0,则将 a 排序为小于 b 的索引,即 a 排在第一位。
  • 如果 compareFunction(a, b) 返回 0,则保持 ab 彼此不变,但相对于所有不同的元素进行排序。
  • 如果 compareFunction(a, b) 大于 0,则排序 b 到小于 a 的索引,即 b 排在第一位。

但是,您的函数返回二进制 truefalse,与数字相比,它们的计算结果分别为 10。这有效地将比较归结为n1

如果数组小于11个元素,ChromeV8的排序例程会立即切换到插入排序,并且不执行快速排序步骤:

// Insertion sort is faster for short arrays.
if (to - from <= 10) {
  InsertionSort(a, from, to);
  return;
}

V8 的插入排序实现只关心比较器函数是否将 b 报告为大于 a,对 0

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

这保证了对 [1,3,2,4] 等数组的准确排序,并且注定了具有 10 个以上元素的数组至少要有一个几乎肯定不准确的快速排序步骤。

更新7/19/19:由于本文中讨论了V8(6)的版本,V8的数组排序的实现在7.0中移动到了Torque/Timsort,正如本文中所讨论的,插入排序在长度为22或更小的数组上调用

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

< code > array . prototype . sort 和< code > typed array . prototype . sort 依赖于用JavaScript编写的相同快速排序实现。排序算法本身相当简单:其基础是快速排序,对于较短的数组(长度

不管实现细节有什么变化,如果排序比较器遵循标准,代码将按可预测的方式排序,但如果比较器没有履行约定,所有的赌注都将落空。

 类似资料:
  • 问题内容: 我经常在PHP中看到包含include.inc文件的示例。.inc是什么意思?它的作用是什么?使用它的缺点和优点是什么? 问题答案: 它没有任何意义,只是一个文件扩展名。如果扩展名是.inc的文件被设计为包含在其他PHP文件中,这是某些人的惯例,但这只是惯例。 它确实存在一个可能的缺点,即通常没有将服务器配置为将.inc文件解析为php,因此,如果该文件位于您的Web根目录中,并且您的

  • Apache CouchDB是最新的数据库之一。 CouchDB具有无模式的文档模型,更适合常见应用。可支持非常大数据量查询。 使用CouchDB的主要原因是什么? CouchDB易于使用。 有一个单词可以描述CouchDB - “Relax”。 它也是组成CouchDB官方标志一个单词。 “Apache CouchDB已经开始了,现在是放松时间。” CouchDB具有基于HTTP的REST AP

  • DevOps允许敏捷开发团队实施持续集成和持续交付。这有助于他们更快地将产品推向市场。 其他一些的重要原因是: 可预测性:DevOps可以显着降低新版本的故障率 再现性:版本一切,以便可以随时恢复早期版本。 可维护性:在新版本崩溃或禁用当前系统的情况下,可以毫不费力地进行恢复。 交付/上市时间:DevOps通过简化的软件交付将上市时间缩短至50%。对于数字和移动应用尤其如此。 更高的质量:DevO

  • Akka平台提供哪些有竞争力的特性? Akka提供可扩展的实时事务处理。 Akka为以下目标提供了一致的运行时与编程模型: 垂直扩展(并发) 水平扩展(远程调用) 高容错 这个模型是唯一需要学习和掌握的,它具有高内聚和高一致的语义。 Akka是一种高度可扩展的软件,这不仅仅表现在性能方面,也表现在它所适用的应用的大小。Akka的核心——akka-actor是非常小的,可以方便地加入你的应用中,提供

  • 问题内容: serialVersionUID缺少a时,Eclipse发出警告。 问题答案: 首先,我需要解释什么是序列化。 序列化 允许将对象转换为流,以便通过网络发送该对象,或者保存到文件或保存到DB以供使用。 有一些序列化规则。 仅当对象的类或其超类实现接口时,该对象才可序列化 一个对象是可序列化的(本身实现了接口),即使其超类不是。但是,可序列化类的层次结构中的第一个超类(不实现Serial

  • 问题内容: 我正在研究THREE.js,并注意到其中定义函数的模式如下: 这种方法的 正常 变化如下所示: 将第一个版本与 正常 版本进行比较,第一个版本似乎有所不同: 它分配一个自动执行功能的结果。 它在此函数内定义了局部变量。 它返回包含使用局部变量的逻辑的 实际 函数。 因此,主要的区别在于,在第一个变体中,初始化时,bar仅分配一次,而第二个变体在每次调用时都会创建此临时变量。 关于为什么

  • 本文向大家介绍为什么要使用 kafka,为什么要使用消息队列?相关面试题,主要包含被问及为什么要使用 kafka,为什么要使用消息队列?时的应答技巧和注意事项,需要的朋友参考一下 缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够多的机器来保证冗余,kafka在中间可以起到一个缓冲的作用,把消息暂存在kafka中,下游服务就可以按照自己的节奏进行慢慢处理。 解耦和扩展性:项目开始的

  • 问题内容: 我注意到,Oracle JDK中使用了许多Java 8方法,如果给定的对象(参数)为,则会在内部抛出该方法。 但是,如果取消引用对象,则将被抛出。那么,为什么要做这个额外的null检查并抛出 ? 一个明显的答案(或好处)是它使代码更具可读性,我同意。我很想知道在方法开始时使用的其他原因 。 问题答案: 因为您可以这样做使事情变得 明确 。喜欢: 或更短: 现在您 知道了 : 当 成功使