【问题标题】:Quicksort- how pivot-choosing strategies affect the overall Big-oh behavior of quicksort?快速排序 - 枢轴选择策略如何影响快速排序的整体 Big-oh 行为?
【发布时间】:2011-02-15 07:37:09
【问题描述】:

我想出了几个策略,但我不完全确定它们如何影响整体行为。我知道平均情况是 O(NlogN),所以我认为这将在某个地方的答案中。如果我只是选择数组中的第一项作为快速排序的枢轴,我只想放置 NlogN+1,但我不知道这是否正确或可接受?如果有人能在这个问题上启发我,那就太好了。谢谢!

可能的策略:

a) 数组是随机的:选择第一项,因为这是最具成本效益的选择。

b) 数组主要是排序的:选择中间项,因此我们可能会补充每次一分为二的二进制递归。

c) 数组比较大:选择数组中的第一个、中间和最后一个索引并比较它们,选择最小的以确保我们避免最坏的情况。

d) 使用随机生成的索引执行“c”以降低选择的确定性。

【问题讨论】:

  • 我不明白这个问题。
  • 问:对于我选择的可能策略 (a-d),它们将如何影响快速排序算法的整体行为?

标签: java algorithm performance sorting quicksort


【解决方案1】:

您应该知道的一个重要事实是,在不同元素的数组中,随机选择分区的快速排序将在 O(n lg n) 中运行。有很多很好的证明,the one on Wikipedia 实际上对此进行了很好的讨论。如果你愿意去寻求一个稍微不那么正式的证明,这种证明在数学上基本上是合理的,直觉如下。每当我们选择一个支点时,假设一个“好的”支点是一个至少给我们 75%/25% 的支点;也就是说,它大于至少 25% 的元素和最多 75% 的元素。我们想要限制在算法终止之前我们可以获得这种类型的枢轴的次数。假设我们得到 k 个这种类型的拆分,并考虑以这种方式生成的最大子问题的大小。它的大小最多为 (3/4)kn,因为在每次迭代中,我们都会删除至少四分之一的元素。如果我们考虑 k = log3/4 (1/n) = log4/3 n 的具体情况,那么在 k 个好的枢轴之后的最大子问题的大小被选择为 1,递归将停止。这意味着如果我们选择获得 O(lg n) 个好的枢轴,递归将终止。但是在每次迭代中,获得这样一个支点的机会有多大?好吧,如果我们随机选择枢轴,那么它有 50% 的机会位于中间 50% 的元素中,依此类推,我们会在得到一个好的枢轴之前选择两个随机的枢轴。选择支点的每一步都需要 O(n) 时间,因此我们应该在获得每个好的支点之前花费大约 O(n) 时间。由于我们最多获得 O(lg n) 个良好的枢轴,因此总体运行时间为 O(n lg n)。

上述讨论中的一个重要细节是,如果您将 75%/25% 拆分替换为任何恒定拆分 - 例如 (100 - k%) / k% 拆分 - 过渐近分析是相同的。你会得到快速排序平均需要 O(n lg n) 时间。

我提到这个证明的原因是它为您提供了一个很好的框架来思考如何在快速排序中选择一个支点。如果您可以在每个迭代中选择一个非常接近中间的枢轴,则可以保证 O(n lg n) 运行时间。如果您不能保证在任何迭代中都能获得良好的支点,但可以说在获得良好支点之前只需要恒定数量的迭代,那么您还可以保证 O(n lg n)预期运行时间。

鉴于此,让我们来看看您提出的枢轴方案。对于 (a),如果数组是随机的,则选择第一个元素作为枢轴本质上与在每个步骤中选择随机枢轴相同,因此通过上述分析,您将获得 O(n lg n) 运行时间.对于 (b),如果您知道数组大部分是排序的,那么选择中位数是一个不错的策略。原因是,如果我们可以说每个元素“非常接近”它应该在排序序列中的位置,那么你可以论证你选择的每个枢轴都是一个好的枢轴,给你 O(n lg n ) 你想要的运行时。 (“非常接近”这个词在数学上不是很精确,但我认为如果你愿意的话,你可以毫不费力地将其形式化)。

至于 (c) 和 (d),在两者中,(d) 是唯一能保证得到 O(n lg n) 的期望值。如果您确定性地选择某些元素用作枢轴,则您的算法将容易受到确定性序列的影响,这些序列会使其退化为 O(n2) 行为。实际上有一篇非常有趣的论文,名为 "A Killer Adversary for Quicksort",由 McIlroy 撰写,描述了如何采用任何确定性快速排序并通过使用恶意比较函数为其构建病态最坏情况输入。您几乎肯定希望在任何真正的快速排序实现中避免这种情况,否则恶意用户可能会通过输入这些杀手序列来对您的代码发起 DoS 攻击,从而强制您的程序以二次时间排序并因此挂起。另一方面,因为 (d) 是随机选择其样本点,所以它不容易受到这种攻击,因为在任何序列上,枢轴的选择都是随机的。

不过,有趣的是,对于 (d),虽然选择三个随机元素并取中位数并没有什么坏处,但您不需要这样做。较早的证明足以表明,通过单个随机枢轴选择,您将获得 O(n lg n) 的期望值。我实际上不知道选择三个随机值的中值是否会提高快速排序算法的性能,尽管由于快速排序始终为 Ω(n lg n),它肯定不会比仅选择随机元素更好。枢轴。

我希望这会有所帮助 - 我真的很喜欢快速排序算法以及构建良好快速排序实现所涉及的所有设计决策。 :-)

【讨论】:

  • 谢谢,这非常有帮助,我希望你非常喜欢写这篇文章? :)
  • 哦,整个 DoS 攻击真的很有趣!计算机黑客可以用一条简单的信息做什么,真是令人惊讶。
  • @Mr_CryptoPrime- 这写起来很有趣;感谢您提出这么酷的问题!我很高兴你喜欢这个链接——我把它列为我最喜欢的 CS 论文之一。
【解决方案2】:

您必须了解,已经有许多算法可以让您维持 O(nlog(n)) 复杂性。使用randomized quick sort 的预期时间复杂度为 O(nlog(n)),通常被认为比其他方法更好。

如果您将以上所有内容混合使用,您将能够维持 O(nlog(n)),即根据输入数据集的“配置文件”有条件地应用其中一个。话虽如此,对输入数据集进行分类本身就是一项挑战。无论如何,要做得更好,您必须研究您的输入数据集并选择可能的替代方案。

【讨论】:

    【解决方案3】:

    最好的枢轴是可以将数组精确分成两半的枢轴。数组的中位数当然是最好的选择。我会建议这种方法:-
    select some random indexes
    calculate median of these elements
    Use this as pivot element

    从 O(n) 中值查找算法来看,我认为 5 个随机索引应该足够了。

    【讨论】:

    • -1 这种说法似乎没有根据。 O(n) 中值查找算法基于对算法性能的非常仔细的数学分析,选择将序列分成五个元素的块。您可能是正确的,选择五个随机元素的中位数是好的,但您需要支持这一说法。此外,如果您只是要选择随机元素的中位数,为什么不选择随机枢轴呢?这可以被证明以高概率为您提供 O(n lg n) 的预期行为。
    猜你喜欢
    • 2010-09-14
    • 2011-08-31
    • 1970-01-01
    • 1970-01-01
    • 2018-11-14
    • 1970-01-01
    • 2019-11-23
    • 2012-12-20
    • 1970-01-01
    相关资源
    最近更新 更多