【问题标题】:Why is randomised quicksort considered better than standard quicksort?为什么随机快速排序被认为比标准快速排序更好?
【发布时间】:2021-07-27 03:29:45
【问题描述】:

用 Cormen 自己的话来说 - “不同之处在于,使用确定性算法,特定输入可以引发最坏情况的行为。然而,使用随机算法,没有任何输入可以总是引发最坏情况的行为。”

添加随机枢轴如何改变任何事情,算法在某些特定输入下仍然会表现不佳,并且考虑到每种输入的可能性相同,这并不比标准快速排序更好,唯一的区别是我们实际上并没有知道哪个特定输入会导致最坏情况的时间复杂度。那么为什么随机版本被认为更好呢?

【问题讨论】:

  • 少想“意外坏”,多想“我被攻击”坏
  • @MooingDuck 那么这是唯一的优势吗?不过,在现实世界中这真的很重要吗,让快速排序(或任何排序算法)在最复杂的情​​况下运行是否会在潜在的黑客攻击中使用?
  • 事实上,这很重要,它有自己的名字:en.wikipedia.org/wiki/…

标签: algorithm sorting quicksort randomized-algorithm


【解决方案1】:

考虑以下版本的 quicksort,我们总是选择 最后一个元素 作为 pivot。现在考虑以下数组:

int[] arr = {9, 8, 7, 6, 5, 4, 3, 2, 1};

当这个数组使用我们的快速排序版本进行排序时,它总是会选择最小的元素作为它的主元,也就是最后一个元素。在第一次迭代中,它会像这样改变数组:

arr = [1, 8, 7, 6, 5, 4, 3, 2, 9];

现在,它将在子数组上递归:

s1 = [1, 8, 7, 6, 5, 4, 3, 2];
s2 = [9];

s1 中,它将再次选择2 作为其支点,并且只有8 和2 会互换位置。所以,通过这种方式,如果我们尝试制定一个递推关系,由于它的复杂性,它将是

T(n) = T(n-1) + O(n)

对应于O(n^2)

因此,对于这个数组,标准版本总是需要 O(n^2) 时间。

在随机版本中,我们首先将最后一个元素与数组中的一些随机元素交换,然后选择它作为枢轴。因此,对于给定的数组,此枢轴将随机拆分数组,很可能在中间。所以,现在的复发将是

T(n) = 2T(n/2) + O(n)

这将是 O(n * Log(n))

这就是我们认为随机快速排序优于标准快速排序的原因,因为随机快速排序中出现错误拆分的可能性非常低。

【讨论】:

  • 排序序列(在数据中很常见)是快速排序的最坏情况,这一事实很久以前通过选择中值元素作为枢轴来解决。这使得正常数据源的坏情况与随机数据源一样不可能。切换的真正原因是为了避免来自攻击者的不良数据。
  • Charachit,谢谢你,但话又说回来,我的问题是为什么我们认为随机快速排序更好(这里唯一的区别是我们不知道哪个输入发生了最坏的情况,仍然存在发生这种情况的情况,与标准版本相同)所以根据我的说法,它在技术上并没有更好
【解决方案2】:

不同之处在于,使用确定性算法,特定输入可以引发最坏情况的行为。然而,使用随机算法,任何输入都不能总是引发最坏情况的行为。

应该澄清这意味着真正的随机算法。如果改为使用确定性伪随机算法,则故意创建的输入可能会引发最坏情况的行为。

然而,使用随机算法,没有任何输入总是能引发最坏情况的行为。

这应该澄清一下:即使使用真正的随机算法,在使用该输入的一次或多次随机快速排序调用中,仍然存在某些特定输入可能引发最坏情况行为的可能性,但没有任何输入总能引发在同一输入上无限次调用真正随机快速排序的最坏情况。


单枢轴快速排序的大多数库实现使用中位数 3 或中位数 9,因为它们不能依赖于对 X86 RRAND 和快速除法(用于模函数)等随机数提供快速指令。如果快速排序以某种方式成为加密方案的一部分,那么可以使用真正的随机算法来避免基于时间的攻击。

【讨论】: