有没有人知道std::nth_element
的不同实现的预期运行时间和最差情况运行时间?我几乎每天都使用这个算法。
我对最近的Microsoft编译器附带的STL版本特别感兴趣,但有关此主题的任何信息都很有帮助。
Please note that this is not a duplicate of this question.我理解存在哪些算法,但我对哪些实现使用哪种算法感兴趣。
对于背景,有众所周知的算法可以做到这一点。一个是O(n)平均情况和O(n log n)最坏情况,一个是O(n)最坏情况但实际上缓慢(中位数的中位数)。 另请注意there is talk of interesting implementation strategies to get worst-case O(n) running times that are fast in practice。该标准规定,这必须在更短的O(n)平均时间内。
答案 0 :(得分:16)
预计运行时间为O(N) 大多数实现的最坏情况运行时间是O(N * N),因为大多数实现使用QuickSelect,可能是QuickSelect运行到坏分区。 对于Microsoft VS2008,VS2010& VS2012。
现在有了新的ISO C ++ 2011标准,std :: sort的复杂性已经收紧 - 保证为O(N * log N),并且使用David Musser的IntroSort时没有更糟糕的情况: - 使用QuickSort,如果阵列的某些部分遇到错误的分区,请换到heapsort。
理想情况下,应该使用std :: nth_element完全相同,但ISO C ++ 2011标准并没有收紧复杂性要求。因此,在最坏的情况下,std :: nth_element可能是O(N * N)。这可能是因为在David Musser的原始论文中(见here),如果QuickSelect出现问题,他没有提到应该交换哪种算法。
在最坏的情况下,可以使用使用5组的中位数中位数(我已经看过一篇论文推荐的7组但无法找到它)。因此,如果分区变坏,std :: nth_element的质量实现可以使用QuickSelect并交换到中位数中位数。这将保证O(N)行为。 QuickSelect可以通过使用采样来改进,使最坏情况不太可能但不是不可能的。
答案 1 :(得分:7)
GCC 4.7中的实现使用了David Musser的introspective selection(这里有paper提供有关introsort和introselect的详细信息)。根据这些文件,最坏情况下的执行时间是O(n)。
答案 2 :(得分:0)
cppreference说,首先它排序然后找到第n个元素,但通过这种方式,平均值应该是O(n log n)
(通过基于比较的排序算法),但是他们写的平均值是O(n),似乎不正确,除了使用基类排序等排序,...但因为它具有基于通用比较的输入,似乎不可能使用基数排序或任何其他不基于比较的排序。无论如何,使用快速排序算法比在实践中使用正常选择算法(内存和平均时间)更好。