为什么Java6数组#sort(Object[])对于小数组从mergesort更改为insertionsort?

为什么Java6数组#sort(Object[])对于小数组从mergesort更改为insertionsort?,java,algorithm,mergesort,Java,Algorithm,Mergesort,Java 6在数组中的mergesort实现。如果数组长度小于某个阈值,Java将使用插入排序。该值硬编码为7。由于算法是递归的,因此对于大型数组,这种情况最终会发生很多次。canonical不这样做,只是一直使用合并排序,直到列表中只有1个元素 这是一种优化吗?如果是这样,它应该如何帮助?为什么7?插入排序(即使是我的理解是,这是一个经验推导的值,插入排序所需的时间实际上较低,尽管(可能)需要更多的比较。这是因为在mergesort接近尾声时,数据可能几乎被排序,这使得插入排序性能良好。是的,

Java 6在
数组中的mergesort实现。如果数组长度小于某个阈值,Java
将使用插入排序。该值硬编码为7。由于算法是递归的,因此对于大型数组,这种情况最终会发生很多次。canonical不这样做,只是一直使用合并排序,直到列表中只有1个元素


这是一种优化吗?如果是这样,它应该如何帮助?为什么
7
?插入排序(即使是
我的理解是,这是一个经验推导的值,插入排序所需的时间实际上较低,尽管(可能)需要更多的比较。这是因为在mergesort接近尾声时,数据可能几乎被排序,这使得插入排序性能良好。

是的,这是有意的。虽然mergesort的大O小于插入排序等二次排序,但它所做的操作更复杂,因此速度较慢。

考虑对长度为8的数组进行排序。除了7个合并操作外,合并排序还会对自身进行14个递归调用。每个递归调用都会给运行时带来一些不寻常的开销。每个合并操作都涉及一个循环,其中索引变量必须初始化、递增和比较,临时数组必须复制,等等总之,你可以期待超过300个“简单”的操作

另一方面,插入排序本质上很简单,使用大约8^2=64个操作,这要快得多

这样想。当你手工对10个数字的列表进行排序时,你会使用合并排序吗?不会,因为你的大脑更擅长做简单的事情,比如插入排序。但是如果我给你一年时间对10万个数字的列表进行排序,你可能更倾向于合并排序

至于幻数7,经验证明它是最优的


编辑:在8个元素的标准插入排序中,最坏情况下会导致约36次比较。在规范合并排序中,有约24次比较。加上方法调用的开销和操作的复杂性,插入排序应该更快。此外,如果你看一下平均情况,插入排序会产生更少的com小于36的型坯。

插入排序为n(n-1)/2,合并排序为n*(以2为底的对数n)。

考虑到这一点—

  • 对于长度为5=>插入排序=10且合并排序为11.609的数组
  • 对于长度为6=>插入排序=15且合并排序为15.509的数组
  • 对于长度为7=>插入排序=21且合并排序为19.651的数组
  • 对于长度为8=>的数组,插入排序为28,合并排序为24
  • 从上面的数据可以清楚地看出,在长度6之前,插入排序更快,在长度7之后,合并排序更有效


    这就解释了为什么使用7。我也这么想。但当我运行一些基准测试时,我发现情况并非如此。对于便宜的compareTo操作,任何小于20的数字大致相当,对于昂贵的compareTo,比较时间占主导地位。Matthew:请注意,昂贵的
    compareTo
    实现可能并不重要最常见的情况是(请记住,Java的基类库是非常通用的,并不是专门针对您的用例),通过在小的子列表上使用插入排序,您还可以节省重复应用D&C算法或合并排序的开销。@Matthew Joey关于“通用性”的说法是正确的另一点需要注意的是,真正昂贵的
    compareTo()
    方法可能应该是固定的,因为比较两个对象不需要花费很长时间。如果无法避免这一点(可能是因为对象真的很复杂),那么根据相关标准对一组代理对象进行排序可能是值得的(因为排序时很少考虑对象的每一个方面。)明白-我没有试图解决的实际问题;)但该算法仅用于对一般对象进行排序-原语数组的处理方式不同-因此,比较的未知复杂性应该是一个考虑因素,不是吗?调用插入排序时,数据几乎是如何排序的?Mergesort仅在合并阶段进行排序,递归插入排序调用在此之前进行对复杂性的理解从直觉上讲是很有意义的——虽然我无法证明7的任何优势,>25确实起到了作用。编辑了我的答案。我不能100%确定你的基准测试显示了什么,因为你的轴没有真正标记。+1如果你需要对许多小数组进行排序,这会产生非常大的差异。我已经对f这张图的来源是什么?你似乎没有任何评论就展示了它。我制作这张图的方法是对一组对象进行排序,这些对象计算调用compareTo的次数,并改变INSERTIONSORT_阈值。值得注意的是,Java7还有Timsort,这是Tim Peters为Java开发的混合合并插入python