除了中位数算法中,在最坏情况下O(n)时间还有其他方法可以进行k选择吗?实施中位数中位数是否有意义;我的意思是,性能优势是否足以达到实用目的?
答案 0 :(得分:12)
还有另一种基于 soft heap 数据结构计算第k顺序统计数据的算法,该数据结构是标准优先级队列的变体,允许“破坏”某些数量的存储的优先级。该算法在维基百科文章中有更详细的描述,但基本思想是使用软堆有效地(O(n)时间)为分区函数选择一个支点,以保证良好的分割。从某种意义上说,这只是中位数算法的修改版本,它使用(可以说)更直接的方法来选择枢轴元素。
软堆并不是特别直观,但在this paper(“Chazelle的软堆的更简单的实现和分析”)中有一个非常好的描述,其中包括正式描述和分析数据结构
但是,如果您想要一个非常快速,最坏情况的O(n)算法,请考虑查看 introselect 。这个算法实际上非常精彩。它首先使用quickselect algorithm,它非智能地选择一个数据透镜并使用它来分区数据。这在实践中非常快,但具有糟糕的最坏情况行为。 Introselect通过跟踪跟踪其进度的内部计数器来解决此问题。如果算法看起来似乎要降级到O(n 2 )时间,它会切换算法并使用像中位数中值这样的东西来确保最坏情况下的保证。具体来说,它会监视在每一步中丢弃多少数组,如果在丢弃输入的一半之前发生了一些常数步骤,算法会切换到中位数算法,以确保下一个数据集好之前然后使用quickselect重新启动。这可以保证最坏情况下的O(n)时间。
这种算法的优势在于它在大多数输入上都非常快(因为快速选择非常快),但具有很大的最坏情况行为。可以在 in this paper (“内省排序和选择算法”)中找到此算法的描述以及相关的排序算法内容。
希望这有帮助!
答案 1 :(得分:3)
我认为当你的容器中有N百万个元素时,你应该真正测试它并找出性能是什么。该算法已经在STL库(C ++)中实现,因为std::nth_element
被保证为预期的O(n)。因此,如果您使用C ++,您可以轻松地运行一些测试,看看性能是否足以满足您的要求。
一个值得注意的例外是C ++,它提供了一个模板化的nth_element 保证预期线性时间的方法。
答案 2 :(得分:1)
这取决于。如果你担心意外发生的最坏情况,我不会打扰。随着数据变得越来越大以至于需要关注,最坏的情况变得不太可能,因此几乎不值得保护。
如果您在客户端可以提供最坏情况下的数据以在您的服务器上执行拒绝服务的情况下进行选择,则可能值得使用中位数中位数来确保最差 - 大订单不会对性能造成任何影响。
答案 3 :(得分:0)
更新:
有一个线性时间算法,快速排序的修改,由quicksort的发明者Hoare本人建议。
我建议参考CLRS书中的第9.3节“在最坏情况线性时间中选择”。
这是一个简短的算法,假设我们有一个来自quicksort的方法random_partition
(它使用随机数据块进行分区):
FindKth(array, l, u, k)
{
int m = random_partition(array, l, u);
if m == k : return array[k] /*we have found the kth element*/
if m > k: return FindKth(array, l, m-1, k); /* we have found element > kth largest, concentrate on the left partition */
else: return FindKth(array, m+1, u, k-m); /* find the k-m th element in the right partition */
}
你也可以参考Donald Knuth的TAOCP Vol.3排序和搜索p.633 这种方法的优点在于,数组不需要完全排序! 我认为STL nth_permutation使用了这种技术,你可以参考笔记部分。