在尝试估计程序的性能时,我总是将sort()函数视为性能最差的n ^ 2函数。但是,我遇到了一个维基百科页面:
其中说GNU C Library sort()首先使用一些名为Introsort的混合排序算法,然后进行插入排序。 Introsort的相应页面声称该算法具有nlogn的最差情况。但是,由于我不熟悉这个算法,我仍然担心sort():
1)GNU sort()使用的混合算法能否保证O(nlogn)性能?如果是这样,nlogn的持续开销有多大?
2)是否有任何其他实现可能导致sort()执行比这更差(或更好,这会很棒)?
编辑:回复Kevin:提到的sort()是std :: sort()。
谢谢!
答案 0 :(得分:5)
使用quicksort和introsort(这是前者的变体,通过在最坏情况输入时切换到heapsort来实现保证O(n log n)
性能)代替其他理论上更好的算法,例如mergesort,这是由于事实平均情况是相同的,并且常量要低得多(在常量中你可以包括它可以在适当位置排序的事实,因此没有重新分配和副本)。而最糟糕的情况是坏的,但很容易改进。通常,假设sort
的效果为O( n log n )
。
如果你担心隐藏的常数,那么问题不是理论问题,而是性能问题。在尝试优化时,最好在实际数据上测量算法,分析测量结果,然后确定花费的时间以及是否可以改进。但这与理论问题完全不同。
答案 1 :(得分:3)
如果您的标准库不能保证超出ISO 14882,那么sort()
的最坏情况行为似乎没有正式限制 - 只列出了平均复杂度。标准中有一个脚注,提到如果您关心,应使用stable_sort()
或partial_sort()
代替sort()
:
http://www.kuzbass.ru:8086/docs/isocpp/lib-algorithms.html#lib.alg.sorting
25.3.1.1 - sort [lib.sort]
template<class RandomAccessIterator> void sort(RandomAccessIterator first, RandomAccessIterator last) template<class RandomAccessIterator, class Compare> void sort(RandomAccessIterator first, RandomAccessIterator last, Compare comp)
效果:对[first,last]范围内的元素进行排序。
- 醇>
复杂性:大约N log N(其中N == last-first)平均比较。*
[脚注:如果最坏的情况是重要的,应该使用stable_sort()(lib.stable.sort)或partial_sort()(lib.partial.sort)。 ---结束脚注]
特定的库实现可能会提供超出标准的更强保证。直接查看代码肯定是有用的。再说一次,这取决于你想要的便携性。
答案 2 :(得分:2)
Introsort实际上有O(n log(n))最坏情况下的运行时间,而不是O(n ^ 2)。 另请参阅SGI STL规范中的this remark:
早期版本的排序使用了 快速排序算法,使用数据透视表 按中位数选择三个。快速排序 具有O(N log(N))平均复杂度, 但是二次最坏情况的复杂性。 但是,sort的当前实现使用了introsort 算法的算法 最坏情况的复杂性是O(N log(N))。 Introsort非常相似 三分之一的快速排序,现在是 至少和平均快速排序一样快。
答案 3 :(得分:1)
是的,它是快速排序的变体,使用heapsort进行可疑的病态快速输入输入。它着眼于递归深度,当它下降得太深时,它会使用heapsort去除任何病理行为。这保证了N log N.N log N(qsort vs heapsort)的恒定开销不用担心。
当元素很少(约16个)时使用插入排序。
答案 4 :(得分:0)
http://en.wikipedia.org/wiki/Sorting_algorithm列出了几种具有n ^ 2性能的排序算法。它有一个与n!性能。它还列出了几种基于其他因素具有性能的非比较排序。