【问题标题】:Merge-sort for Stacks堆栈的合并排序
【发布时间】:2017-12-26 21:37:04
【问题描述】:

知道为什么我的 Stack 合并排序不起作用吗?它与我的数组合并排序非常相似,但它可以工作。我的递归设置错了吗?

谢谢!

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]

【问题讨论】:

  • 它到底有什么问题?您没有显示任何输入,没有预期的输出,没有实际的输出,没有错误。只是一段代码和“为什么这不起作用?”请相应地编辑您的问题。
  • @DavidMakogon 已修复。
  • 问题没有提到要使用的堆栈数量是否有限制。通常涉及合并排序和堆栈的作业或程序挑战会限制允许的堆栈数量,这需要自下而上的方法,因为自上而下的方法会分配许多堆栈。然而,目标也可能只是处理堆栈的 LIFO 特性。

标签: python sorting merge stack mergesort


【解决方案1】:

我假设您这样做是为了学习归并排序或 LIFO,但如果不是,因为您的 stack 只是一个 python 列表(数组),函数 sorted(s._data)s._data.sort() 都可以满足您的需要。如果您需要继续使用堆栈,那么...

首先,调试:

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

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

由于您使用堆栈 LIFO 执行此操作,因此基于此条件使用 pop()left.top() &lt; right.top(),生成的新堆栈数组变为: [19, -4, 11]。后进先出,意味着一旦 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]

【讨论】:

    猜你喜欢
    • 2015-08-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-19
    • 1970-01-01
    • 2021-08-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多