Stacks的合并排序

时间:2017-07-21 01:08:23

标签: python sorting merge stack mergesort

知道为什么我的Stack合并排序不起作用?它与我对数组的merge-sort非常相似,但是那个有效。我的递归设置错了吗?

谢谢!

def sort(stack):
    if len(stack) > 1:
        middle = len(stack) // 2
        stack_len = len(stack)
        left = Stack()
        right = Stack()
        for i in range(middle):
            left.push(stack.pop())
        for i in range(middle, stack_len):
            right.push(stack.pop())
        sort(left)
        sort(right)
        while(not left.is_empty() and not right.is_empty()):
            if (left.top() < right.top()):
                stack.push(right.pop())
            else:
                stack.push(left.pop())
        while(not left.is_empty()):
            stack.push(left.pop())
        while(not right.is_empty()):
            stack.push(right.pop())

这是我的Stack ADT实现:

class Stack:

    def __init__(self):
        self._data = []

    def __len__(self):
        return len(self._data)

    def is_empty(self):
        return len(self) == 0

    def push(self, i):
        self._data.append(i)

    def pop(self):
        if not self.is_empty():
           return self._data.pop()
        raise IndexError('Cannot pop an empty Stack.')

    def top(self):
        if not self.is_empty():
            return self._data[len(self) - 1]
        raise IndexError('Cannot check the top of an empty Stack.')

我的测试用例是:

if __name__ == '__main__':
    s = Stack()
    s.push(8)
    s.push(0)
    s.push(-4)
    s.push(11)
    s.push(19)
    s.push(21)
    s.push(3)
    s.push(14)
    s.push(1)
    s.push(14)
    print(s._data)
    sort(s)
    print(s._data)

给出:

[8, 0, -4, 11, 19, 21, 3, 14, 1, 14]

[19, 14, 1, 21, 3, 14, -4, 8, 0, 11]

1 个答案:

答案 0 :(得分:2)

我假设你这样做是为了学习合并排序或LIFO,但如果没有,因为你的stack只是一个python列表(数组),函数sorted(s._data)s._data.sort()都是完成你需要的。如果你需要继续堆栈那么......

首先,调试:

如果您想了解错误,可以放置一些print()语句,以便在代码的每个阶段查看堆栈的外观。您的排序功能很好,并且可以正确地分离您的阵列。该缺陷在合并部分。算法的合并部分发生在使用3 while循环的部分递归调用sort()之后。最后,通过示例输入,将合并这些数组:

MERGING
L [19]
R [11, -4]

由于您使用堆栈LIFO执行此操作,因此基于此条件pop()使用left.top() < right.top(),生成的新堆栈数组变为:  [19, -4, 11]。 Last in,First,out,表示一旦Left数组为空,就会添加第二个,因为Right被清空。但是,通过适当的合并,此数组将被合并排序,并且应该合并为:

[-4, 11, 19]

您的下一次合并是:

MERGING
L [8, 0]
R [19, -4, 11]

这导致新堆栈为:[11, 0, 8, -4, 19],最终导致19被添加到最终堆栈中,因此19在结果中位于索引0的位置,您得到:{{ 1}}

解决:

要解决此问题,您应该使用[19, 14, 1, 21, 3, 14, -4, 8, 0, 11]代替FIFO,并且始终将最小的数字添加到队列中,该队列将位于数组的索引0处(即从左侧移动)到右)。如果您绝对必须使用queue并继续使用stackappend方法,那么,我建议:

首先,在合并部分中,合并较小的数字,优先级高于较高的数字。然后,在从左侧或右侧数组添加到合并部分中的堆栈之前,您需要确保要添加的数字大于堆栈的当前头部(Last in)。如果它不是更大,那么你需要将.pop()堆栈放入一个新数组或左/右数组(你没有使用哪个数组),直到下一个添加的值实际上大于堆栈的头部。然后,继续使用相同的方法,只向堆栈添加大于堆栈头部的值,记住将pop'd值也按正确的顺序添加回堆栈。

代码更新解决方案

以下是添加的代码作为维护堆栈方法的解决方案:

pop()

更新解决方案:while(not left.is_empty() and not right.is_empty()): if (left.top() > right.top()): if stack.is_empty() or stack.top() <= right.top(): stack.push(right.pop()) else: left.push(stack.pop()) else: if stack.is_empty() or stack.top() <= left.top(): stack.push(left.pop()) else: right.push(stack.pop()) while(not left.is_empty()): if stack.is_empty() or stack.top() <= left.top(): stack.push(left.pop()) else: right.push(stack.pop()) while(not right.is_empty()): if stack.is_empty() or stack.top() <= right.top(): stack.push(right.pop()) else: left.push(stack.pop()) while(not left.is_empty()): stack.push(left.pop())