【问题标题】:using insertion sort once in quicksort在快速排序中使用一次插入排序
【发布时间】:2014-10-21 16:55:44
【问题描述】:

根据here

使用插入排序...用于小数组的调用(即 长度小于通过实验确定的阈值 k)。这 可以通过在小于 k 时简单地停止递归来实现 元素被留下,整个数组被 k 排序:每个元素 距离其最终位置最多 k 个位置。然后,一个 单次插入排序通过在 O(k×n) 时间内完成排序。

我不确定我的理解是否正确。一种涉及多次调用插入排序的方法是

quicksort(A, i, k):
  if i+threshold < k:
    p := partition(A, i, k)
    quicksort(A, i, p - 1)
    quicksort(A, p + 1, k)
  else
    insertionsort(A, i, k)

但这会为每个子数组调用insertionsort()。听起来插入排序只能调用一次,但我有点不明白这一点,因为插入排序被调用多少次并不重要,它通常仍然比快速排序慢。

是这样的想法吗?

sort(A)
 quicksort(A, 0, A.length-1)
 insertionsort(A, 0, A.length-1)

所以基本上在最后调用一次插入排序?你怎么知道它只需要通过一次而不是 O(n) 运行?

【问题讨论】:

    标签: algorithm sorting pseudocode


    【解决方案1】:

    是的,您的第二个伪代码是正确的。插入排序的通常分析是,外循环依次插入每个元素(O(n) 次迭代),内循环将该元素移动到正确位置(O(n) 次迭代),总共 O(n ^2)。但是,由于您的第二个quicksort 留下了一个数组,该数组可以通过在最大threshold 大小的块内排列元素进行排序,因此每个元素最多移动threshold 位置,并且新的分析是O(n*threshold),这是等效的分别对每个块运行插入排序。

    由 Bentley 在 1999 年版的 Programming Pearls 中描述,这个想法(根据维基百科)避免了多次启动和停止插入排序循环的开销(本质上,我们已经在大批)。恕我直言,这是一个可爱的想法,但考虑到现在商品硬件的性能特征有多么不同(具体而言,最终的插入排序需要再次传递数据,这已经变得相对更昂贵,以及启动成本)循环(在寄存器中移动一些值)变得相对便宜)。

    【讨论】:

    • 想详细说明您指的是哪些性能特征?当然,对碰巧在缓存中的元素进行插入排序更有意义,因为它们刚刚被分区,但是您还有其他想法吗?
    • @rici 与内存引用相比,在寄存器中随机排列几个值的成本变得相对便宜。
    • 另一方面,错过分支预测的成本变得更加昂贵。每次循环结束时,插入测试中的循环结束测试很可能被预测错误;在单次插入排序版本中,这只发生一次。当然,如果没有基准,这一切都只是空洞的猜测。
    • @rici 是的,谁知道呢?出于这个原因,我非常温和地表达了我的批评。
    • @DavidEisenstat 你刚刚复制了我的问题。你的伪代码和我的有什么不同?你所说的快速排序-粗略我称之为排序。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-06-30
    • 2020-07-30
    • 2012-10-06
    • 2023-04-06
    • 2011-11-30
    • 1970-01-01
    • 2013-02-25
    相关资源
    最近更新 更多