如果比较函数不可传递,Array.sort()的行为如何?

时间:2016-10-22 23:33:48

标签: javascript algorithm sorting graphics 3d

我正在编写一个算法来对3D盒子的数组进行排序,以便按照从前到后的顺序进行绘制。有一种定义明确,稳定的方法可以决定两个方框中的哪一个位于另一个方框的前面,因此我编写了一个函数来执行该操作,然后将函数传递给Array.prototype.sort()以获得正确的绘制顺序

three boxes overlap each other

但是可以设置框的周期,使A>BB>CC>A都为真。这意味着整个列表没有明确定义的排序顺序,即使任何一对的顺序都是明确定义的。

在实践中,这种情况不大可能出现,如果确实如此,我可以忍受一两个盒子的顺序错误。但是,在这种情况下,是否存在可以对整个列表进行错误排序或崩溃的JS实现?

11月10日更新

现在只需填写更多上下文,项目就完成了(事实上,如果你愿意,没有理由你不能look at it):

我问这个问题的原因是,虽然明显的答案是“你不能使用破坏的比较器排序”,但仍然......这是一个类似排序的任务,并试图进行排序 会给出一些有用的结果。

在我的具体应用中,上面显示的循环情况从未实际出现过(至少,你必须真正尝试)。我希望我可以对对象进行排序,这样,如果删除了属于循环的任何元素,剩下的元素将按严格的顺序排列。但我没有达到这一点,这就是原因:

我的第一个想法是,当我比较两个方框时,无论哪个方框位于X轴前面 Y轴,Z轴都在前面排序。但这意味着我不是比较框(A),而是真正比较无限的交叉形状(B): Overlapping boxes

- 这意味着它们像疯了一样重叠,而且循环情况并不罕见;事实上,如果有3个或更多个对象,我不妨使用随机顺序。

在某些时候我看到了this helpful reference,这表明我应该只测试在屏幕上实际重叠的成对方框。添加该测试(并且如果它们不重叠则排序框为“相等”)会产生更好的结果,框中的顺序通常不正确,但仍然存在大量错误。

问题是快速排序算法不会测试每一对可能的值(如果他们这样做,他们将是O(n 2 ))。将A和B排序为“相等”并不仅仅意味着它们的相对顺序并不重要;这意味着如果C在A之前排序,它也必须在B之前排序。无论浏览器使用什么类型的算法,它都会跳过基于此假设的比较,因此它不会测试我需要它来测试的每对盒子

最后,我编写了我自己的无用的,天真的排序代码(测试每个框,直到找到重叠)。我的屏幕上永远不会有超过40个对象,所以性能还可以,而且结果经常是正确的。一个更彻底的算法会涉及回溯,并会引发暂停问题,所以我就此止步了。

所以,这不是最令人满意的结论,但有时它会如何发展。无论如何,希望这会为其他人提供一些帮助(或残酷的娱乐)。

1 个答案:

答案 0 :(得分:1)

如果排序不具有传递性 - 如您所说,类型允许循环关系<?xml version="1.0" encoding="UTF-8"?> <map> <entry> <string>PNB_ALERTLOG_RECEIVER_CHANNEL</string> <com.mirth.connect.util.ConfigurationProperty> <value>PNB_ALERTLOG_RECEIVER</value> <comment>Canal que...</comment> </com.mirth.connect.util.ConfigurationProperty> </entry> <entry> <string>PNB_CFG_FILE_ACCESS_CONTROL</string> <com.mirth.connect.util.ConfigurationProperty> <value>resources/configPnbDev/pnbAccessControl.json</value> <comment>Este ficheiro...</comment> </com.mirth.connect.util.ConfigurationProperty> </entry> </map> - 那么我不知道这些项目的顺序是错误的:-)

ECMAScript标准(ECMA-262,5.1版)says of Array.prototype.sort

  

如果A > B ; B > C ; C > A未定义,并且不是此数组元素的一致比较函数(见下文),则comparefn的行为是实现定义的。

并且“见下文”解释了,是的,比较的传递性需要 comparefn 才有资格作为“一致”。

  

如果满足以下所有要求,函数sort是一组值comparefn的一致比较函数[...]

     
      
  • 如果Sa =CF b,则b =CF ca =CF c的及物性传承
  •   
  • 如果=CFa < CF b,则b <\ CF ca <\ CF c的及物性传承
  •   
  • 如果<\ CFa >CF b,则b >CF ca >CF c的及物性传承
  •   

因此,正如您所描述的那样,您的非传递性比较函数会调用规范的“实现定义”子句。

我建议将“实现定义”读作“可以做任何事情或者什么也不做,不可预测,并且仍然符合此规范”。