堆栈的归并排序

Merge-sort for Stacks

知道为什么我的堆栈合并排序不起作用吗?它与我的数组合并排序非常相似,但它确实有效。我的递归设置错误吗?

谢谢!

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]

我假设您这样做是为了学习合并排序或后进先出法,但如果不是,因为您的 stack 只是一个 python 列表(数组),函数 sorted(s._data)s._data.sort() 两者都能满足您的需求。如果您需要继续使用堆栈,那么...

首先调试:

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

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

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

[-4, 11, 19]

你的下一个合并是:

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

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

解析:

要解决这个问题,您应该改用 queue,这将是 FIFO,并且您总是首先将最小的数字添加到队列中,它位于数组的索引 0 处(即移动从左到右)。如果您绝对必须使用 stack 并继续使用 append.pop() 方法,那么,我建议:

首先,在合并部分,合并较小的数字,优先级高于较大的数字。然后,在合并部分从 Left 或 Right 数组添加到堆栈之前,您需要确保添加的数字大于堆栈的当前头部(Last in)。如果不大于,则需要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())

更新解决方案:[-4, 0, 1, 3, 8, 11, 14, 14, 19, 21]