Mergesort堆栈(仅使用额外堆栈,但需要尽可能多)

时间:2017-03-06 19:53:27

标签: algorithm sorting recursion heap

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

  

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

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

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

使用4个堆栈和自下而上的合并排序会更快。调用堆栈A,B,C和D,数据最初位于堆栈A(B,C,D为空)。将元素(pop / push)从A交替分割为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。将元素(pop / push)从A交替分割为B和C.然后将B中的元素与C中的元素合并,并将结果推入A,从而导致A中的大小为2的排序运行。然后再次分割A ,这次只是在将两个元素从A移动到B并将两个元素从A移动到C之间交替。然后"运行"大小为2的大小从B和C合并回A,创建大小为4的运行。由于元素在从A移动到B或C时以相反的顺序被推动,因此需要反转比较的意义,例如使用> ;替换< =用于升序(或原始订单,如果相等)排序。除非使用单个链表实现堆栈,否则B,C的大小需要与A相同。这大约是4堆栈版本的两倍,因为在每次合并传递之后,数据必须从A重新分配到B和C.

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

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