有一个与数组相关的问题,要求时间复杂度为O(n),空间复杂度为O(1)。
如果我使用Arrays.sort(arr)
,并使用for
循环到一个传递循环,例如:
public static int hello(int[]A){
Arrays.sort(A);
for(int i=0;i<A.length;i++){
....................
}
return ....;
}
这个循环的时间复杂度是O(n)。Arrays.sort()
会花费更多的时间吗?如果我使用Arrays.sort()
,这个时间复杂度还是O(n)吗?Arrays.sort()
会花费更多的空间吗?
7条答案
按热度按时间qvsjd97n1#
我假设您在这里谈论的是Java。
那么循环将花费O(n)时间,我的问题是Arrays.sort()会花费更多时间吗?
是的,在我所知道的所有Java标准库实现中,
Arrays.sort(int[])
是基于比较的排序的一个例子,因此必须具有最坏情况的复杂度Ω(n log n)。特别是,Oracle Java 7使用双主元快速排序变体来处理整数重载,它实际上具有 Ω(n2) 最坏情况。Arrays.sort()会占用更多的空间吗?
它很可能会使用ω(1)空间(这意味着另一个yes,空间使用量不是O(1)),虽然实现基于比较的排序并不是不可能的,但它是非常不切实际的。
也就是说,在某些条件下,可以在线性时间内对特定类型的数据进行排序,例如参见:
对于一个固定范围的输入整数(例如,对于某个常数C,
abs(A[i]) <= C
),计数排序和基数排序实际上只使用O(n)时间和O(1)空间,所以这可能是有用的。ghhkc1vu2#
根据java jvm 8 javadocs的
Arrays.sort()
方法:排序算法是由弗拉基米尔Yaroslavskiy、Jon Bentley和约书亚Bloch提出的Dual-Pivot Quicksort算法,该算法在许多数据集上提供O(n log(n))的性能,而这些数据集会导致其他快速排序降低到二次性能,并且该算法通常比传统的(单枢轴)快速排序实现更快。
因此,时间复杂度将从
O(n)
增加到O(n log(n))
r7s23pms3#
Arrays.sort(int[] a)在最近的JDK中是用双枢轴快速排序算法实现的,该算法具有O(n log n)的平均复杂度并且是就地执行的(例如不需要额外的空间)。
zkure5ic4#
这需要O(n)的时间,也需要O(1)的空间。
Arrays.sort()利用1.7中的修改Timsort,这是最近开发的排序算法,它提供复杂度为x的排序,其中O(n)〈x〈O(nlgn),空间为O(n/2)
v8wbuo2f5#
既然你是用Java语言来讨论它,那么时间复杂度肯定会从O(n)增加到O(nlogn),这是因为在Java 8中,Arrays.sort()是用双主元快速排序算法实现的,而不是单主元,所以需要额外的时间,而空间复杂度O(1)是不可能的,因为它需要更多的空间,我猜是O(n/2)。
blmhpbnm6#
数组排序(int [])
以及Arrays. sort(long [])、Arrays. sort(float [])和Arrays. sort(double [])
时间复杂度
Arrays.sort(int[])
的时间复杂度取决于Java的版本。我们使用了一个非常普通的快速排序,其时间复杂度从O(n)(当数组已经排序并且我们只检查它是否排序时)到O(n2),对于某些输入,它会导致元素在各个部分中的分布极其不均匀,平均复杂度为O(n log(n))。
时间复杂度O(n log(n))
在Java 14中,这个实现得到了改进,以保证最坏情况下的时间复杂度为O(n log(n))。函数是changed,用于在递归变得太深时求助于堆排序:
这防止了该方法降低到二次时间复杂度。
"瞥见未来"
有一个initiative可以切换到基数排序,用于几乎随机的足够大的数组,从而在最坏的情况下将时间复杂度降低到O(n)。
时间复杂度O(n)
在所有版本中,算法的空间复杂度范围从O(1)(当数组已经排序并且我们只需要检查它是否排序时)到O(n)(当数组高度结构化时(原始数组中有少量排序的子数组并且我们合并这些子数组))。
以下是最坏情况下的分配:
DualPivotQuicksort.java
数组. sort(短整型[])
以及Arrays. sort(char [])和Arrays. sort(byte [])
时间复杂度O(n),空间复杂度O(1)
尽管文件上说:
排序算法是由Vladimir Yaroslavskiy、Jon Bentley和Joshua Bloch提出的Dual-Pivot Quicksort,该算法在所有数据集上提供O(n log(n))性能,并且通常比传统的(单枢轴)Quicksort实现更快。
至少从Java 7开始就不是这样了。实际上,一个用于足够大的数组的就地counting sort具有线性时间复杂度和常量空间复杂度:
计数排序实现
数组. sort(对象[])
与其他方法不同的是,这个方法有很好的文档记录,并且这里的文档符合实际情况。
时间复杂度O(n log(n))
这种实现是一种稳定的、自适应的、迭代的合并排序,当输入数组部分排序时,它需要的比较次数远少于n次lg(n),而当输入数组随机排序时,它提供了传统合并排序的性能。如果输入数组接近排序,则该实现需要大约n次比较。
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#sort(java.lang.Object[])
排序算法是一种改进的合并排序算法(如果低位子列表中的最高元素小于高位子列表中的最低元素,则省略合并)。该算法提供了有保证的n * log(n)性能。
https://docs.oracle.com/javase/6/docs/api/java/util/Arrays.html#sort(java.lang.Object[])
时间复杂度O(n)
临时存储要求从几乎排序的输入数组的一个小常量到随机排序的输入数组的n/2个对象引用不等。
https://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html#sort(java.lang.Object[])
java.util.Arrays. sort和(间接)java.util.Collectionsort使用的对对象引用进行排序的算法是一种"修改的合并排序(其中,如果低位子列表中的最高元素小于高位子列表中的最低元素,则省略合并)"。它是一种相当快的稳定排序,保证了O(n log n)的性能,但需要O(n)的额外空间。
https://bugs.openjdk.org/browse/JDK-6804124
368yc8dk7#