【问题标题】:Observing quadratic behavior with quicksort - O(n^2)使用快速排序观察二次行为 - O(n^2)
【发布时间】:2011-01-16 22:11:11
【问题描述】:

quicksort 算法的平均时间复杂度为 O(n*log(n)),最坏情况复杂度为 O(n^2)。

假设 Hoare 的快速排序算法有一些变体,什么样的输入会导致快速排序算法表现出最坏情况的复杂性?

请说明与特定快速排序算法(例如枢轴选择等)的实现细节相关的任何假设,或者它是否来自诸如 libc 等常用库。

一些阅读:

  1. A Killer Adversary for Quicksort
  2. Quicksort Is Optimal
  3. Engineering a Sort Function
  4. Introspective Sorting and Selection Algorithms

【问题讨论】:

  • 论文中概述的攻击的前提是能够运行任意可执行代码,而他们能想出的最好办法就是让快速排序变成二次方?
  • 我建议 - 如果某件事听起来像家庭作业,则应在问题后 1-2 周内回答。虽然现在 SO 几乎可以解决所有问题,所以可能为时已晚......

标签: c++ algorithm sorting complexity-theory quicksort


【解决方案1】:

Quick sort执行最差IE,即在所选枢轴的所有值是所采用的集合中最大或最小的o(n ^ 2)。考虑这个例子。

1 2 3 4 5

选择的枢轴是 1,枢轴右侧将有 4 个元素,左侧没有元素。递归地应用相同的逻辑并且选择的枢轴分别为 2、3、4、5,我们已经达到了这种排序在最坏的时间执行的情况。

已经推荐并证明,如果输入被很好地洗牌,则快速排序会表现良好。

此外,排序的选择通常取决于对输入域的清晰了解。例如,如果输入很大,那么有一种称为外部排序的东西可能会使用外部存储器。如果输入大小非常小,我们可能会使用归并排序,但不适用于中型和大型输入集,因为它使用额外的内存。快速排序的主要优点是它的“就地”意义,没有额外的内存被用于输入数据。它在纸上的最坏情况时间是 O(n^2),但仍然被广泛首选和使用。我的观点是,排序算法可以根据输入集的知识及其偏好进行更改。

【讨论】:

  • 为什么 shuffle 让它更快?
  • @MariusKavansky:排序算法通常不固定。我们正在谈论对大量数据应用策略。如果您对输入集的情况有所了解,则可以有效地选择排序方法。由于上述枢轴选择逻辑,快速排序在部分排序的数据上表现不佳。但是,如果输入集完全打乱,则选择枢轴无效的概率是最小的。这就是 Shuffle 让它变得更快(如果不是理想的话)的原因。
【解决方案2】:

扩展 Bragboy 所说的内容,而不是只跑:

quicksort(array);

运行:

shuffle(array);
quicksort(array);

shuffle() 的定义可能是:

shuffle(array){
    for(int i = array.length; i > 0; i--){
        r= random number % i;
        swap(array[i], array[r]);
    }
}

这样做很可能会处理获取输入导致quicksort() 变慢的情况。

【讨论】:

  • 感谢您的信息,但问题是关于构建特定类型的输入,这些输入会导致快速排序的行为呈二次方。
  • @Joren:你会如何改进它?
  • @Zenikoder:我知道,我只是在说明 shuffle 是如何工作的。 Bragboy 的回答很好,我只是在添加更多细节。
  • 通过实施 Fisher-Yates 洗牌。你的有 n^n 个可能的代码路径,而只有 n 个!不同的排列。显然,它不能为所有排列提供相等的概率。
  • @MariusKavansky:对数组进行改组可以加快排序速度,因为通过改组,您可以合理地确保避免快速排序具有 O(n^2) 性能的边缘情况 (en.wikipedia.org/wiki/Quicksort?#Choice_of_pivot)跨度>
【解决方案3】:

Hoare 的快速排序算法选择一个随机枢轴。对于可重现的结果,我建议 Scowen 的修改,除其他外,从输入中选择中间项目。对于这个变体,具有最小枢轴的锯齿模式似乎是最坏情况的输入:

starting with           {  j   i   h   g   f   a   e   d   c   b  }
compare 1 to 6          { (j)  i   h   g   f  (a)  e   d   c   b  }
compare 6 to 10         {  j   i   h   g   f  (a)  e   d   c  (b) }
compare 6 to 9          {  j   i   h   g   f  (a)  e   d  (c)  b  }
compare 6 to 8          {  j   i   h   g   f  (a)  e  (d)  c   b  }
compare 6 to 7          {  j   i   h   g   f  (a) (e)  d   c   b  }
swap 1<=>6              { (a)  i   h   g   f  (j)  e   d   c   b  }
compare 1 to 5          { (a)  i   h   g  (f)  j   e   d   c   b  }
compare 1 to 4          { (a)  i   h  (g)  f   j   e   d   c   b  }
compare 1 to 3          { (a)  i  (h)  g   f   j   e   d   c   b  }
compare 1 to 2          { (a) (i)  h   g   f   j   e   d   c   b  }
compare 2 to 6          {  a  (i)  h   g   f  (j)  e   d   c   b  }
compare 3 to 6          {  a   i  (h)  g   f  (j)  e   d   c   b  }
compare 4 to 6          {  a   i   h  (g)  f  (j)  e   d   c   b  }
compare 5 to 6          {  a   i   h   g  (f) (j)  e   d   c   b  }
compare and swap 6<=>10 {  a   i   h   g   f  (b)  e   d   c  (j) }
compare 7 to 10         {  a   i   h   g   f   b  (e)  d   c  (j) }
compare 8 to 10         {  a   i   h   g   f   b   e  (d)  c  (j) }
compare 9 to 10         {  a   i   h   g   f   b   e   d  (c) (j) }
compare 2 to 6          {  a  (i)  h   g   f  (b)  e   d   c   j  }
compare 6 to 9          {  a   i   h   g   f  (b)  e   d  (c)  j  }
compare 6 to 8          {  a   i   h   g   f  (b)  e  (d)  c   j  }
compare 6 to 7          {  a   i   h   g   f  (b) (e)  d   c   j  }
swap 2<=>6              {  a  (b)  h   g   f  (i)  e   d   c   j  }
compare 2 to 5          {  a  (b)  h   g  (f)  i   e   d   c   j  }
compare 2 to 4          {  a  (b)  h  (g)  f   i   e   d   c   j  }
compare 2 to 3          {  a  (b) (h)  g   f   i   e   d   c   j  }
compare 3 to 6          {  a   b  (h)  g   f  (i)  e   d   c   j  }
compare 4 to 6          {  a   b   h  (g)  f  (i)  e   d   c   j  }
compare 5 to 6          {  a   b   h   g  (f) (i)  e   d   c   j  }
compare and swap 6<=>9  {  a   b   h   g   f  (c)  e   d  (i)  j  }
compare 7 to 9          {  a   b   h   g   f   c  (e)  d  (i)  j  }
compare 8 to 9          {  a   b   h   g   f   c   e  (d) (i)  j  }
compare 3 to 6          {  a   b  (h)  g   f  (c)  e   d   i   j  }
compare 6 to 8          {  a   b   h   g   f  (c)  e  (d)  i   j  }
compare 6 to 7          {  a   b   h   g   f  (c) (e)  d   i   j  }
swap 3<=>6              {  a   b  (c)  g   f  (h)  e   d   i   j  }
compare 3 to 5          {  a   b  (c)  g  (f)  h   e   d   i   j  }
compare 3 to 4          {  a   b  (c) (g)  f   h   e   d   i   j  }
compare 4 to 6          {  a   b   c  (g)  f  (h)  e   d   i   j  }
compare 5 to 6          {  a   b   c   g  (f) (h)  e   d   i   j  }
compare and swap 6<=>8  {  a   b   c   g   f  (d)  e  (h)  i   j  }
compare 7 to 8          {  a   b   c   g   f   d  (e) (h)  i   j  }
compare 4 to 6          {  a   b   c  (g)  f  (d)  e   h   i   j  }
compare 6 to 7          {  a   b   c   g   f  (d) (e)  h   i   j  }
swap 4<=>6              {  a   b   c  (d)  f  (g)  e   h   i   j  }
compare 4 to 5          {  a   b   c  (d) (f)  g   e   h   i   j  }
compare 5 to 6          {  a   b   c   d  (f) (g)  e   h   i   j  }
compare and swap 6<=>7  {  a   b   c   d   f  (e) (g)  h   i   j  }
compare and swap 5<=>6  {  a   b   c   d  (e) (f)  g   h   i   j  }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-04-01
    • 2020-06-20
    • 2021-12-22
    • 1970-01-01
    • 2020-09-26
    • 2012-07-13
    • 1970-01-01
    相关资源
    最近更新 更多