【问题标题】:Why don't we use quick sort on linked list?为什么我们不在链表上使用快速排序?
【发布时间】:2018-05-14 19:11:51
【问题描述】:

快速排序算法可以分为以下几个步骤

1) 识别支点。

2) 基于pivot对链表进行分区。

3) 将链表递归地分成两部分。

现在,如果我总是选择最后一个元素作为枢轴,那么识别枢轴元素(第一步)需要 O(n) 时间。

识别出枢轴元素后,我们可以存储它的数据并将其与所有其他元素进行比较以识别正确的分区点(第二步)。每次比较都需要 O(1) 时间,因为我们存储了数据透视数据,每次交换需要 O(1) 时间。因此,n 个元素总共需要 O(n) 时间。

所以递归关系是

T(n) = 2T(n/2) + n 即 O(nlogn),与链表的归并排序相同。

那么为什么对于链表来说,合并排序优于快速排序呢?

【问题讨论】:

  • 链表首选合并排序 - 需要引用。
  • 我投票决定将此问题作为题外话结束,因为这个问题最好发给Computer Science 网站。
  • @tadman 我不能在这里问算法和时间复杂度问题吗?这个网站上有很多这样的问题。
  • 由于没有提供引用,我自己查了一下,very first result 声明 链表的缓慢随机访问性能使得其他一些算法(如快速排序)表现不佳,而其他(如堆排序)完全不可能.
  • 我以前做过,效果很好。我想说的主要障碍是应用更高级/棘手的枢轴选择算法的实际效率低下。如果没有随机访问,即使是简单的三中位数也需要完整通过列表。然而,像 stackoverflow.com/questions/40622430/… 这样的最近趋势可能会使这一点过时。

标签: algorithm sorting time-complexity


【解决方案1】:

所以递归关系是... O(nlogn)

对数组的最坏情况快速排序是 O(n^2),例如,每个递归级别只会将最大分区的大小减少 1 或 2(如果两个分区中不包含枢轴,则为 2)。

那么为什么对于链表来说,合并排序优于快速排序呢?

它更快,尤其是自下而上的合并排序,它消除了扫描列表以拆分它们。相反,它使用一个小的(26 到 32 个)内部指针数组或对节点的引用(或小列表数组),将节点合并到数组中,然后合并数组以创建排序列表。 Wiki 文章包含伪代码:

https://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation_using_lists

【讨论】:

  • 我知道每次随机访问都需要 O(n) 时间在链表中。但在我看来,每次比较都需要 O(1) 时间,而不是 O(n)。你能指出快速排序中哪一步在链表中比在数组中需要更多时间吗?
  • @Zephyr - 考虑最坏的情况示例,每个递归级别的最大分区仅减少 1,这意味着 n-1 级递归和(n-1-递归级别)比较对于每个级别的递归,时间复杂度为 O(n^2)。
  • 是的,最坏情况的复杂度是 O(n^2)。但即使在链表中,它也应该是 O(n^2) 。我不明白链表中的 O(n^3) 是怎么回事。
  • @Zephyr - 我更新了我的答案并删除了对 O(n^3) 的引用。我在想另一种情况。
  • @Zephyr - 你可以做一个快速排序的变体来消除交换,但它仍然具有 O(n^2) 的最坏情况时间复杂度。对于每一级递归,将第一个节点作为枢轴,并创建3个列表,节点枢轴。递归用于第一个和第三个子列表,然后将三个列表链接在一起。
【解决方案2】:

现在,如果我总是选择最后一个元素作为枢轴,那么识别枢轴 元素(第 1 步)需要 O(n) 时间。

实际上需要 O(1) 时间。但无论如何,一个常见的误解 w.r.t.快速排序是您可以选择一个预定义元素作为枢轴的想法,而不是随机的。你可能不会。

快速排序平均在 O(N log(N)) 中工作,但最坏的情况是 O(N^2)。现在,当枢轴被随机选择并且算法在大集合上执行时——那么实际上 O(N log(N)) 就是你在实践中得到的。但是,如果您选择一个预定义的支点,那么根据您的数据模式,您很容易遇到最坏的情况。 认为源数据是随机的,它来自某个来源,并表现出某种模式。

例如,如果您将最后一个元素作为枢轴,并且您的源数据以防万一已经按相反顺序排序 - 那么您肯定会得到 O(N ^2)。

关于您的问题,为什么快速排序通常不用于链接列表。原因(恕我直言)是对于列表,合并排序是一种首选方式。它保证了 O(N log(N)) 的最坏情况性能。它通常不用于数组,因为在数组的情况下它需要分配额外的内存,但链表不是这种情况。

【讨论】:

    猜你喜欢
    • 2011-07-10
    • 1970-01-01
    • 2015-02-10
    • 2011-06-02
    • 1970-01-01
    • 1970-01-01
    • 2013-02-15
    • 1970-01-01
    相关资源
    最近更新 更多