【问题标题】:Mergesort stack (using only extra stacks, but with as many as needed)合并排序堆栈(仅使用额外的堆栈,但根据需要使用尽可能多的堆栈)
【发布时间】:2017-07-26 20:09:31
【问题描述】:

我正在阅读Cracking the Coding Interview的一个问题,作者将标题中描述的问题的解决方案描述如下:

使用归并排序解决方案,我们将创建两个额外的堆栈并将堆栈一分为二。 > 零件。我们将递归地对每个堆栈进行排序,然后将它们按排序顺序重新合并到原始堆栈中。请注意,这需要为每个递归级别创建两个额外的堆栈。

我试图了解时间复杂度。我假设(尽管可能完全错误)需要两个额外的堆栈,因为当以自下而上的升序合并两个堆栈时,我们必须反复将两个堆栈中的最小元素弹出到堆栈 2,然后弹出所有堆栈 2进入堆栈 1 以获取所有元素的升序。对于每个递归级别,此过程都是 O(N),并且由于我们在一半上进行递归操作,因此它将是 O(logN) 级别..正确吗?那么这是一个 O(NlogN) 时间算法吗?以及 O(N) 空间复杂度?

【问题讨论】:

    标签: algorithm sorting recursion


    【解决方案1】:

    首先,请注意,每个创建的堆栈都是父堆栈大小的一半。每个递归级别的堆栈大小总和为 N。这使您的空间复杂度为 O(N log N)。

    但是,您可以做得更好。如果将每个堆栈分成两部分(在向下的过程中)并在合并它们时(在向上的过程中)回收子堆栈,则确实可以将空间保持在 O(N)。

    【讨论】:

      【解决方案2】:

      使用 4 个堆栈和自下而上的归并排序会更快。调用堆栈 A、B、C 和 D,数据最初位于堆栈 A(B、C、D 为空)。将 A 中的元素(pop / push)拆分为 C 和 D(1 个元素到 C,1 个元素到 D,...)。然后从 C 和 D 合并运行,在 A 和 B 之间交替合并运行输出(第一次将 2 个元素传递给 A,2 个元素传递给 B,...)。然后从 A 和 B 合并运行,将输出交替输出到 C 和 D(第二遍,4 个元素到 C,4 个元素到 D,...)。重复这个过程,直到只有一个排序的运行。每次“通过”时,比较的意义都会反转(对于 C,D -> A,B 反转,对于 A,B -> C,D 不反转)。 B、C、D 的大小需要与 A 相同,除非堆栈是使用单链表实现的。相同的逻辑可以用于 4 个 FIFO 队列,只是永远不需要反转比较的意义。


      对于 3 堆栈自底向上合并排序,调用堆栈 A、B、C,数据最初位于 A,(B,C 为空)。将 A 中的元素(pop / push)交替拆分为 B 和 C。然后将 B 中的一个元素与 C 中的一个元素合并,并将结果推送到 A 中,从而在 A 中产生大小为 2 的排序运行。然后再次拆分 A ,只有这一次在将两个元素从 A 移动到 B 和将两个元素从 A 移动到 C 之间交替。然后大小为 2 的“运行”从 B 和 C 合并回 A,创建大小为 4 的运行。由于元素被推送在从 A 移动到 B 或 C 时以相反的顺序,需要颠倒比较的意义,例如使用 > 替换


      对于 3 栈排序,一种称为多相归并排序的自底向上归并排序的变体是最快的方法,因为它只需要一次分布,但多相 3 栈排序很复杂。 3 堆栈多相归并排序几乎与 4 堆栈常规自下而上归并排序一样快。哪个更快取决于元素的数量是合并友好(2 的幂)还是多相友好(斐波那契数)。

      http://en.wikipedia.org/wiki/Polyphase_merge_sort

      【讨论】:

        猜你喜欢
        • 2017-12-26
        • 2011-06-17
        • 2015-01-14
        • 2021-09-03
        • 2019-03-08
        • 2021-11-02
        • 2020-11-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多