Arrays.sort(int[])
除了Arrays.sort(long[])、Arrays.sort(float[])和Arrays.sort(double[])之外,
时间复杂度
Arrays.sort(int[])
的时间复杂度取决于Java的版本。
在Java 14之前为O(n2)
使用普通的快速排序算法,时间复杂度范围从O(n)(当数组已经排序并且我们只是检查它时)到某些输入导致元素极不均匀地分布到具有平均复杂度O(n log(n))的部分,其复杂度为O(n2)。您可以在这里找到详细的分析。
从Java 14开始为O(n log(n))
在Java 14中,实现得到改进以保证O(n log(n))的最坏时间复杂度。如果递归变得太深,该函数将
更改为
使用堆排序:
if ((bits += DELTA) > MAX_RECURSION_DEPTH) {
heapSort(a, low, high);
return;
}
这可以防止该方法退化为二次时间复杂度。
展望未来
有一个initiative计划,针对几乎随机的足够大的数组转换到基数排序,从而将时间复杂度降低到最坏情况下的O(n)。
O(n)空间
在所有版本中,算法的空间复杂度范围从O(1)(当数组已经排序并且我们只需要检查它是否已排序)到O(n)(当数组高度结构化时(原始数组中有少量已排序的子数组,并且我们合并这些子数组))。
以下是最坏情况下分配发生的位置:
if (count > 1) {
int[] b; int offset = low;
if (sorter == null || (b = (int[]) sorter.b) == null) {
b = new int[size];
} else {
offset = sorter.offset;
}
mergeRuns(a, b, offset, 1, sorter != null, run, 0, count);
}
return true;
DualPivotQuicksort.java
虽然这个问题特别针对Arrays.sort(int[])方法,但我仍然决定包括其他数据类型的答案,因为当你在谷歌搜索Arrays.sort()时间和空间复杂度时,这是第一个结果,并且在其他地方很难找到正确的答案。
Arrays.sort(short[])
除了 Arrays.sort(char[]) 和 Arrays.sort(byte[]) 之外
O(n) 时间复杂度,O(1) 空间复杂度
虽然文档中说:
排序算法是 Vladimir Yaroslavskiy、Jon Bentley 和 Joshua Bloch 的双轴快速排序。该算法在所有数据集上都能提供 O(n log(n)) 性能,并且通常比传统(单轴)快速排序实现更快。
但至少从 Java 7 开始这是不正确的。实际上,对于足够大的数组使用原地 计数排序 ,其具有线性时间复杂度和恒定空间复杂度:
private static void countingSort(short[] a, int low, int high) {
int[] count = new int[NUM_SHORT_VALUES];
for (int i = high; i > low; ++count[a[--i] & 0xFFFF]);
if (high - low > NUM_SHORT_VALUES) {
for (int i = MAX_SHORT_INDEX; --i > Short.MAX_VALUE; ) {
int value = i & 0xFFFF;
for (low = high - count[value]; high > low;
a[--high] = (short) value
);
}
} else {
for (int i = MAX_SHORT_INDEX; high > low; ) {
while (count[--i & 0xFFFF] == 0);
int value = i & 0xFFFF;
int c = count[value];
do {
a[--high] = (short) value;
} while (--c > 0);
}
}
}
计数排序实现
Arrays.sort(Object[])
与其他方法不同,这个方法有很好的文档记录,并且这里的文档与现实相符。
O(n log(n)) 时间复杂度
从Java 7开始
这个实现是一个稳定的、自适应的、迭代的归并排序,在输入数组部分排序时需要比n lg(n)更少的比较,同时在输入数组随机排序时提供传统归并排序的性能。如果输入数组几乎排序,该实现需要大约n次比较。
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#sort(java.lang.Object[])
Java 7之前
排序算法是修改后的归并排序(如果低子列表中的最高元素小于高子列表中的最低元素,则省略合并)。该算法提供了保证的n*log(n)性能。
https://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html#sort(java.lang.Object[])
O(n) 空间
从 Java 7 开始
临时存储需求因输入数组的排序程度而异,对于几乎有序的输入数组,要求的常量很小,而对于随机排序的输入数组,则需要 n/2 个对象引用。
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#sort(java.lang.Object[])
在Java 7之前
java.util.Arrays.sort和(间接地)java.util.Collections.sort使用的算法,用于对对象引用进行排序,是一种“修改后的归并排序(如果低子列表中的最高元素小于高子列表中的最低元素,则省略合并操作)”。它是一种相对快速且稳定的排序算法,保证O(n log n) 的性能,并需要额外的O(n) 空间。
https://bugs.openjdk.org/browse/JDK-6804124
Arrays.sort()
使用了某些魔法,否则我认为关于它具有最低时间复杂度的问题是可以回答的,不是吗? - O. R. MapperArrays.sort
,因此使用任何算法。很难确定这是什么语言(猜测是Java),但标准库排序几乎总是比较排序。 - user2357112Arrays.sort
的时间和空间复杂度是什么?”,这实际上是一个没有研究努力的问题,因为这已经有相当充分的文献资料。 - Bernhard Barker