【问题标题】:Insertion Sort with binary search带二分查找的插入排序
【发布时间】:2013-08-04 00:53:07
【问题描述】:

在实现插入排序时,可以使用二进制搜索来定位数组的前 i - 1 个元素中的位置,其中元素 i 应插入其中。

这将如何影响所需的比较次数?使用这种二分查找会如何影响插入排序的渐近运行时间?

我很确定这会减少比较次数,但我不确定为什么。

【问题讨论】:

  • 二分查找位置取 O(log N) 比较。这使得孔排序的 O(N.log(N)) 比较。 [我们可以忽略 N 在插入时从 1 增长到最后的 N]
  • 由于插入,算法仍然是 O(n^2)。因此,虽然二分查找可以减少时钟时间(因为比较次数较少),但它不会减少渐近运行时间。
  • @Derrek Whistle:回答已更新
  • 重新打开,因为“重复”似乎根本没有提及比较次数或运行时间。

标签: algorithm sorting binary-search insertion-sort


【解决方案1】:

直接来自维基百科:

如果比较的成本超过交换的成本,情况就是这样 例如,通过引用或人工存储的字符串键 交互(例如选择并排显示的一对中的一个), 那么使用二进制插入排序可能会产生更好的性能。 二进制 插入排序采用二进制搜索来确定正确的 插入新元素的位置,因此执行 ⌈log2(n)⌉ 最坏情况下的比较,即 O(n log n)。该算法作为 整体的平均运行时间仍然为 O(n2),因为 每次插入都需要一系列交换。

来源:

http://en.wikipedia.org/wiki/Insertion_sort#Variants

这是一个例子:

http://jeffreystedfast.blogspot.com/2007/02/binary-insertion-sort.html

我很确定这会减少比较次数,但我 不完全确定为什么。

好吧,如果您已经知道插入排序和二分搜索,那么它就非常简单了。当您在插入排序中插入一个片段时,您必须与之前的所有片段进行比较。假设您要将这个 [2] 移动到正确的位置,您必须比较 7 件才能找到正确的位置。

[1][3][3][3][4][4][5] ->[2]

但是,如果您在中途点开始比较(如二分搜索),那么您只会比较 4 件!你可以这样做,因为你知道左边的部分已经是有序的(如果部分是有序的,你只能进行二进制搜索!)。

现在想象一下,如果您有数千件(甚至数百万件),这将为您节省大量时间。我希望这有帮助。 |=^)

【讨论】:

  • 它仍然没有解释为什么它实际上是 O(n^2),而且维基百科没有引用这句话的来源。
  • @mattecapu 插入排序是一种经过大量研究的算法,已知的最坏情况为 O(n^2)。使用二分搜索来支持插入排序可以缩短时钟时间,但在更坏的情况下仍需要进行相同数量的比较/交换。直观地说,可以将二分搜索作为插入排序的微优化。
  • 对,我没有意识到你真的需要大量的交换来移动元素。所以这些句子似乎都很模糊。抱歉粗鲁。
  • 如果在链表上应用插入排序,那么最坏情况的时间复杂度将是 (nlogn) 和 O(n) 最佳情况,这将是相当有效的。
  • 但正如 wiki 所说,我们不能随机访问以在链表上执行二进制搜索
【解决方案2】:

如果你有一个用于高效二分查找的良好数据结构,那么插入时间不太可能是 O(log n)。相反,在任意位置快速插入的良好数据结构不太可能支持二分查找。

要使用插入排序实现最佳比较搜索的 O(n log n) 性能,需要 O(log n) 二分查找和 O(log n) 任意插入。

【讨论】:

  • 如果使用平衡二叉树作为数据结构,这两个操作都是O(log n)。
  • 但是,你刚刚实现了堆排序。
  • @OscarSmith 但堆不提供 O(log n) 二进制搜索。至少二叉堆和二项堆都没有这样做。堆只保存不变量,即父级大于子级,但是当它小于父/根时,您不知道要在堆中找到元素X 去哪个子树。我想说,HeapSort 是对 SelectionSort 而不是 InsertionSort 的改进,因为在选择排序中,我们正在从 [i:n-1] 的子数组中寻找下一个最大/最小的数字,但是堆允许我们找到下一个最大/分钟并在 O(log n) 时间内将其删除
  • @OscarSmith,如果您使用树作为数据结构,您将实现二叉搜索树而不是堆排序。
【解决方案3】:

二进制插入排序 - 取这个数组 => {4, 5 , 3 , 2, 1}

现在在主循环中,假设我们在第三个元素。现在使用二分搜索,我们将知道在哪里插入 3,即在 4 之前。

二分搜索使用 O(Logn) 比较,这是一个改进,但我们仍然需要在正确的位置插入 3。为此,我们需要将 3 与 5 交换,然后与 4 交换。

由于插入所花费的时间与没有二分搜索的情况相同,因此最坏情况下的复杂度仍然是 O(n^2)。 我希望这会有所帮助。

【讨论】:

    【解决方案4】:

    假设数组已排序(用于执行二进制搜索),它不会减少任何比较,因为内部循环在 1 次比较后立即结束(因为前一个元素更小)。一般来说,插入排序中的比较次数最多为反转次数加上数组大小 - 1。

    由于已排序数组中的反转次数为 0,因此已排序数组中的最大比较次数为 N - 1。

    【讨论】:

    • 插入排序使已处理的元素保持排序。这并不意味着在开始时 whole 数组已经排序。如果是这样,您将不需要排序:/
    • 这是一个有趣的答案,对已排序的数组进行排序。
    • 最坏的情况是,如果您已经为许多排序算法进行了排序并且这根本不好笑,有时您会被要求对恰好已经排序的用户输入进行排序。 +1
    【解决方案5】:

    为了比较,我们有 log n 时间,swap 将是 n 的顺序。 对于最坏情况下的 n 个元素:n*(log n + n) 是 n^2 的顺序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-20
      • 1970-01-01
      相关资源
      最近更新 更多