Java 7是否使用Tim Sort for Method Arrays.Sort?

时间:2010-10-25 19:57:33

标签: java arrays sorting timsort

我找不到Java 7的文档,我只能找到关于Java 6的文档,它仍然可以快速或合并。有谁知道如何在Java 7中找到方法Arrays.sort的文档?

3 个答案:

答案 0 :(得分:79)

Java 7使用Dual-Pivot Quicksort作为基元,使用TimSort作为对象。

根据Java 7 API doc for primitives:

  

实施说明:排序   算法是一个Dual-Pivot Quicksort by   Vladimir Yaroslavskiy,Jon Bentley,   和约书亚布洛赫。这个算法   提供许多O(n log(n))性能   导致其他快速排序的数据集   降低到二次性能,   并且通常比...更快   传统(单枢轴)Quicksort   的实施方式。

根据Java 7 API doc for objects:

  

实施改编自   蒂姆彼得斯的Python排序(   TimSort)。它使用彼得的技术   麦克罗伊的“乐观排序和   信息理论复杂性“,in   第四届年度会议录   ACM-SIAM离散研讨会   算法,第467-474页,1993年1月。

Timsort是一种混合“合并排序和插入排序。”

不确定这与Java 6中的情况有什么不同,for Arrays.sort JDK6:

  

改编自Jon L.的精选快速排行   Bentley和M. Douglas McIlroy的   “设计排序功能”,   软件实践与经验,卷。   23(11)P。1249-1265(1993年11月)

对于Object []或集合(Collections.sort()),使用合并排序。

答案 1 :(得分:20)

是的,Java 7将使用Timsort for Arrays.sort。这是提交: http://hg.openjdk.java.net/jdk7/jdk7/jdk/rev/bfd7abda8f79

答案 2 :(得分:20)

是! ......也没有。

摘要

在当前的Open JDK 0 实现中,Tim Sort通常用于排序对象数组(即Arrays.sort(Object[])和朋友) - 但对于原始数组(其余的Arrays.sort方法)使用了各种其他方法。

对于原语,启发式选择品种的排序方法,如快速排序,合并排序,计数排序 3 。取决于正在排序的数据。大多数这些决策都是根据要排序的数组的类型和大小预先制作的,但对于intlong元素,决策实际上是基于测量的数组排序性而自适应的。因此,在适应/内省(TimSort或类似的合并排序)的基础上,您可以在很多情况下进行自适应/内省(选择算法的启发式方法)!

详细信息

Tim Sort用于大多数对象,例如Arrays.sort(Object[] a),除非用户通过将系统属性java.util.Arrays.useLegacyMergeSort设置为true来专门请求遗留行为。

对于原语,情况更复杂。至少从JDK 8(版本1.8.0_111)开始,根据被排序的数组的大小,原始类型和测量的"排序性"来使用各种各样的heurstics。数组。这是一个概述:

  • 对于除字节 1 以外的所有基本类型,使用插入排序简单地对少于47个元素的数组进行排序(请参阅DualPivotQuicksort.INSERTION_SORT_THRESHOLD)。在使用合并或快速排序时出现的子阵列排序以及子阵列的大小低于阈值时,使用此阈值 。因此,某种形式的插入排序将在所有种类中使用,对于小型数组,它是唯一使用的算法。
  • 对于原始类型byteshortcharcounting sort用于较大的数组。这是一个需要O(n + range)时间的简单排序,其中range是字节总数(256)或短/字符(65536)值。排序涉及分配range值的基础数组,因此仅在要排序的元素数量占总范围的重要部分时使用。特别是,它用于大于29个元素的字节数组(即范围的~11%),以及大于3200个元素的短/字符数组(约为范围的5%)。
  • 对于字节数组,始终使用上述两种方法之一。
  • 对于高于插入排序阈值的intlong数组以及高于插入排序阈值且低于计数排序阈值的short / char数组,其中一个可以使用两种算法:双枢轴快速排序或合并排序。使用哪一个取决于数组排序的度量:输入分为升序或降序元素的运行。如果此类运行的数量大于66,则该阵列主要被视为未排序,并使用双轴快速排序进行排序。否则,数组被认为主要是排序的,并使用mergesort(使用已经枚举的运行作为起点)。

查找运行的想法然后使用mergesort对它们进行排序实际上与TimSort非常相似,尽管存在一些差异。因此,至少对于某些参数,JDK使用的是运行感知的mergesort,但对于许多其他参数组合,它使用的是不同的算法,并且总共使用了至少5种不同的算法!

原理

Object[]与原语的不同排序行为背后的原因可能至少有两倍:

1)Object[]的各种类型必须稳定:同等排序的对象将以与输入相同的顺序出现。对于原始数组,不存在这样的概念:基元完全由它们的值定义,因此稳定和不稳定排序之间没有区别。这允许原始类型免除了对速度有利的稳定算法的需要。

2)Object[]种类需要涉及Object.compare()方法,这可能是任意复杂和昂贵的。即使compare()方法很简单,通常也会有方法调用开销,除非整个排序方法可以内联 2 。因此,Object[]种类通常会偏向于最小化总体比较,即使以一些额外的算法复杂性为代价。

另一方面,各种原始数组只是直接比较原始值,这些原始值通常采用一个或两个循环的顺序。在这种情况下,应该考虑比较的成本和周围的算法来优化算法,因为它们可能具有相同的幅度。

0 至少对于Java 7和Java 9之间的版本,当然这也包括Oracle的JDK,因为它基于Open JDK。 可能其他实现使用类似的方法,但我还没有检查过。

1 对于字节数组,插入排序阈值实际上是29个元素,因为它是使用计数排序的低截止值。

2 这似乎不太可能,因为它非常大。

3 计数排序仅用于16位或更低范围相对有限的值:byteshortchar