我最近阅读了许多关于JavaScript排序的答案,我经常偶然发现一个看起来像这样的比较函数:
array.sort(function(a,b){ a > b ? 1 : -1; });
因此,如果a
大于b
,则比较函数返回1;如果a
小于等于b
,则返回-1。如MDN(link)所述,比较函数也可以返回零,以确保两个项目的相对位置保持不变:
如果compareFunction(a,b)返回0,则保持a和b不变 相互尊重,但相对于所有不同的排序 元件。
所以官方的例子看起来更像是这样:
function compare(a, b) {
if (a < b) return -1;
if (a > b) return 1;
return 0;
}
事实上,通过添加return 0
语句,排序算法通常需要更少的迭代并且总计运行得更快(JSPerf)。
所以我想知道省略return 0
声明是否有任何好处。
我意识到在MDN上,它也说:
注意:ECMAscript标准不保证这种行为,并且 因此并非所有浏览器(例如Mozilla版本至少可以追溯到 2003)尊重这一点。
引用行为,如果返回0,则a
和b
应保持不变。那么也许,通过返回0,我们在不同的浏览器中得到一个稍微不同的排序数组?这可能是个原因吗?是否有任何其他充分理由不返回零?
答案 0 :(得分:10)
所以我想知道在省略return 0语句方面是否有任何优势。
输入更少的字母。由于省略了一个比较,它可能会快一点。所有其他影响都是缺点。
我意识到在MDN上,它也说:
注意:ECMAscript标准不保证这种行为,并且 因此并非所有浏览器(例如Mozilla版本至少可以追溯到 2003)尊重这一点。
指的是行为,如果为0,则a和b应保持不变 归还。
a
和b
的位置可能保持不变只是stable sort的要求。这不是指定的行为,有些浏览器实现了非稳定的排序算法。
但是,返回零的实际目的是a
在b
之前没有排序(好像小于0),b
在a
之前排序(好像大于0) - 基本上当a
等于b
时。这是必须进行比较,所有排序算法都遵守它。
要生成有效,可满足的排序(数学上:将项目划分为totally ordered等价类),比较必须具有某些属性。它们在spec for sort
中列为“一致比较函数”的要求。
最突出的是反身性,要求项a
等于a
(本身)。另一种说法是:
compare(a, a)
必须始终返回0
比较函数不满足时会发生什么(就像你偶然发现的那样)?
规范说
如果
comparefn
[...]不是此数组元素的一致比较函数,sort
的行为是实现定义的。
基本上意味着:如果提供无效的比较函数,则数组可能无法正确排序。它可能会被随机置换,或sort
调用甚至可能无法终止。
所以也许,通过返回0,我们会略有不同 在不同浏览器中排序数组?这可能是个原因吗?
不,通过返回0,您可以跨浏览器获得正确排序的数组(由于排序不稳定,可能会有所不同)。原因是如果不返回0,你会得到略微不同的置换数组(如果有的话),甚至可能产生预期的结果,但通常是以更复杂的方式。
那么如果你没有为同等物品返回0会发生什么?有些实现没有问题,因为它们从不将项目与自身进行比较(即使在数组中的多个位置显而易见) - 可以优化这一点并省略对比较函数的代价高昂的调用,因为已知结果必须是0。
另一个极端是永不停止的循环。假设你有两个相同的项目,你会将后者与前者进行比较,并意识到你必须交换它们。再次测试,后者仍然比前者小,你必须再次交换它们。等等...
但是,一个高效的算法 尽管如此,它可能会做更多或更少的实际上不必要的掉期,因此需要比使用一致的比较功能更长的时间。
还有其他很好的理由不归零吗?
懒惰并希望数组不包含重复项。
答案 1 :(得分:3)
比较方法应遵守合同
Math.sign(compare(a, b)) = -Math.sign(compare(b, a))
如果在== b时返回非零答案,则违反该合同。