用 Python 实现堆栈

Posted

技术标签:

【中文标题】用 Python 实现堆栈【英文标题】:Implementing Stack with Python 【发布时间】:2013-08-19 05:47:40 【问题描述】:

我正在尝试使用数组使用 Python 实现一个简单的堆栈。我想知道是否有人可以让我知道我的代码有什么问题。

class myStack:
     def __init__(self):
         self = []

     def isEmpty(self):
         return self == []

     def push(self, item):
         self.append(item)

     def pop(self):
         return self.pop(0)

     def size(self):
         return len(self)

    s = myStack()
    s.push('1')
    s.push('2')
    print(s.pop())
    print s

【问题讨论】:

docs.python.org/2/tutorial/… 即使您的代码设法将您的对象变成一个列表,这是否意味着您失去了所有自定义方法? 应该只是 pop() 而不是 pop(0)。 pop(0) 使它成为一个队列。 【参考方案1】:

堆栈是一个容器(线性集合),其中动态集合操作 按照后进先出(LIFO)原则进行。 只有一个指针——top,用于执行这些操作

使用数组实现堆栈的CLRS:

class Stack:
    """
    Last in first out (LIFO) stack implemented using array.
    """
    def __init__(self, capacity=4):
        """
        Initialize an empty stack array with default capacity of 4.
        """
        self.data = [None] * capacity
        self.capacity = capacity
        self.top  = -1

    def is_empty(self):
        """
        Return true if the size of stack is zero.
        """
        if self.top == -1:
            return True
        return False

    def push(self, element):
        """
        Add element to the top.
        """
        self.top += 1
        if self.top >= self.capacity:
            raise IndexError('Stack overflow!')
        else:
            self.data[self.top] = element

    def pop(self):
        """
        Return and remove element from the top.
        """
        if self.is_empty():
            raise Exception('Stack underflow!')
        else:
            stack_top = self.data[self.top]
            self.top -= 1
            return stack_top

    def peek(self):
        """
        Return element at the top.
        """
        if self.is_empty():
            raise Exception('Stack is empty.')
            return None
        return self.data[self.top]

    def size(self):
        """
        Return the number of items present.
        """
        return self.top + 1

测试实现:

def main():
    """
    Sanity test
    """
    stack = Stack()

    print('Size of the stack is:', stack.size())
    stack.push(3)
    print('Element at the top of the stack is: ', stack.peek())
    stack.push(901)
    print('Element at the top of the stack is: ', stack.peek())
    stack.push(43)
    print('Element at the top of the stack is: ', stack.peek())
    print('Size of the stack is:', stack.size())
    stack.push(89)
    print('Element at the top of the stack is: ', stack.peek())
    print('Size of the stack is:', stack.size())
    #stack.push(9)    # Raises IndexError
    stack.pop()
    print('Size of the stack is:', stack.size())
    stack.pop()
    print('Size of the stack is:', stack.size())
    stack.pop()
    print('Size of the stack is:', stack.size())
    print('Element at the top of the stack is: ', stack.peek())
    stack.pop()
    #print('Element at the top of the stack is: ', stack.peek())    # Raises empty stack exception

if __name__ == '__main__':
    main()

【讨论】:

【参考方案2】:
class Stack:
   s =[]

   def push(self, num):
       self.s.append(num)

   def pop(self):
       if len(self.s) == 0: # erro if you pop an empty list
           return -1
       self.s.remove(self.s[-1])

   def isEmpty(self):
       if len(self.s) == 0:
           return True
       else:
           return False

   def display(self): # this is to display how a stack actually looks like
       if self.isEmpty():
           print("Stack is Empty")
    
       for i in range(len(self.s)-1,-1,-1): # I haven't used reversed() since it will be obv
           print(self.s[i])


obj = Stack()
obj.push(3)
print(obj.isEmpty())
obj.push(4)
obj.display()
print("----")
obj.pop()
obj.display()

【讨论】:

【参考方案3】:

我想分享我的继承 Python List 的堆栈实现版本。我相信堆栈上的迭代应该以 LIFO 顺序发生。此外,应提供对pop-all() 的迭代以在弹出所有元素时进行迭代。我还添加了stack.clear() 来清空堆栈(就像我们在集合模块中的deque.clear() 中一样)。出于调试目的,我还覆盖了__repr__

class Stack(list):

    def push(self, item):
        self.append(item)

    def top(self):
        return self[-1]

    def size(self):
        return len(self)

    def isempty(self):
        return self.size() == 0

    def __iter__(self):
        """ iter in lifo """
        return super(Stack, self).__reversed__()

    def __reversed__(self):
        return super(Stack, self).__iter__()

    def popall(self):
        try:
            while True:
                yield self.pop()
        except IndexError:
            pass

    def clear(self):
        del self[:]

    def __repr__(self):
        if not self:
            return '%s()' % self.__class__.__name__
        return '%s(%s)' % (self.__class__.__name__, super(Stack, self).__repr__())

这里是你如何使用它:

stack = Stack(range(5))
print "stack: ", stack  # stack:  Stack([0, 1, 2, 3, 4])

print "stack.pop() => ", stack.pop() # stack.pop() =>  4
print "stack.push(20) " # stack.push(20) 
stack.push(20)
for item in stack:
    print item  # prints 20, 3, 2... in newline
print "stack: ", stack # stack:  Stack([0, 1, 2, 3, 20])
print "stack pop all..."
for item in stack.popall(): # side effect to clear stack
    print item
print "stack: ", stack # stack:  Stack()

主要,我实现它是为了解决编程问题next greater element。

【讨论】:

【参考方案4】:

我在下面纠正了一些问题。此外,在抽象编程术语中,“堆栈”通常是您从顶部添加和删除的集合,但您实现它的方式是添加到顶部并从底部删除,这使其成为队列.

class myStack:
     def __init__(self):
         self.container = []  # You don't want to assign [] to self - when you do that, you're just assigning to a new local variable called `self`.  You want your stack to *have* a list, not *be* a list.

     def isEmpty(self):
         return self.size() == 0   # While there's nothing wrong with self.container == [], there is a builtin function for that purpose, so we may as well use it.  And while we're at it, it's often nice to use your own internal functions, so behavior is more consistent.

     def push(self, item):
         self.container.append(item)  # appending to the *container*, not the instance itself.

     def pop(self):
         return self.container.pop()  # pop from the container, this was fixed from the old version which was wrong

     def peek(self):
         if self.isEmpty():
             raise Exception("Stack empty!")
         return self.container[-1]  # View element at top of the stack

     def size(self):
         return len(self.container)  # length of the container

     def show(self):
         return self.container  # display the entire stack as list


s = myStack()
s.push('1')
s.push('2')
print(s.pop())
print(s.show())

【讨论】:

要使其成为栈,pop函数应该是def pop(self): return self.container.pop(-1) @Sanju 或只是self.container.pop() 为什么最后打印输出“<__main__.mystack object at>”? AttributeError: 'Stack' 对象没有属性 'stack' .. 检查你的 show(self) 函数 @Brionius,啊,这是我的错!我没有包含size 方法:) 这就是问题所在。【参考方案5】:

下面是我的实现

class Stack:
    def __init__(self):
        self.items = list()
    def is_empty(self):
        return self.items == []
    def peek(self):
        if self.is_empty():
            print('Cannot peek empty stack')
            return
        else:
            return self.items[-1]
    def pop(self):
        if self.is_empty():
            print('Cannot pop an empty stack')
            return
        else:
            return self.items.pop()
    def size(self):
        return len(self.items)
    def push(self,data):
        self.items.append(data)

【讨论】:

【参考方案6】:

正确的实现应该包括__iter__,因为 Stack 需要是 LIFO 顺序。

class Stack:
    def __init__(self):
        self._a = []

    def push(self, item):
        self._a.append(item)

    def pop(self):
        return self._a.pop()

    def isEmpty(self):
        return len(self._a) == 0

    def __iter__(self):
        return reversed(self._a)

    def __str__(self):
        # return str(list(reversed(self._a)))
        return str(list(iter(self)))

def main():
    stack = Stack()
    stack.push('a')
    stack.push('b')
    stack.push('c')
    stack.pop()
    print(stack)
    if stack:
        print("stack not empty")
    stack.pop()
    stack.pop()
    if stack.isEmpty():
        print("stack empty")

if __name__ == '__main__':
    main()

【讨论】:

【参考方案7】:

Implementing a Stack in Python 来自《用算法和数据结构解决问题》一书中

【讨论】:

【参考方案8】:

下面是python中stack的简单实现。此外,它还返回任意时间点的中间元素。

  class Stack:
        def __init__(self):
            self.arrList = []

        def isEmpty(self):
            if len(self.arrList):
                return False
            else:
                return True

        def push(self, val):
            self.arrList.append(val)

        def pop(self):
            if not self.isEmpty():
                self.arrList[len(self.arrList)-1]
                self.arrList = self.arrList[:len(self.arrList)-1]
            else:
                print "Stack is empty"

        def returnMiddle(self):
            if not self.isEmpty():
                mid = len(self.arrList)/2
                return self.arrList[mid]
            else:
                print "Stack is empty"

        def listStack(self):
            print self.arrList

    s = Stack()
    s.push(5)
    s.push(6)
    s.listStack()
    print s.returnMiddle()
    s.pop()
    s.listStack()
    s.push(20)
    s.push(45)
    s.push(435)
    s.push(35)
    s.listStack()
    print s.returnMiddle()
    s.pop()
    s.listStack()

输出:

[5, 6]
6
[5]
[5, 20, 45, 435, 35]
45
[5, 20, 45, 435]

【讨论】:

【参考方案9】:

您的堆栈是一个数组...

class stacked(): # Nodes in the stack
    def __init__(self,obj,next):
        self.obj = obj
        self.next = next
    def getObj(self):
        return(self.obj)
    def getNext(self):
        return(self.next)

class stack(): # The stack itself
    def __init__(self):
        self.top=None
    def push(self,obj):
        self.top = stacked(obj,self.top)
    def pop(self):
        if(self.top == None):
            return(None)
        r = self.top.getObj()
        self.top = self.top.getNext()
        return(r)

【讨论】:

【参考方案10】:

我在评论中留下了http://docs.python.org/2/tutorial/datastructures.html#using-lists-as-stacks 的链接,但如果您想要一个自定义类型,可以为您提供pushpopis_emptysize 便捷方法,我只需子类list

class Stack(list):
    def push(self, item):
        self.append(item)
    def size(self):
        return len(self)
    def is_empty(self):
        return not self

但是,正如我在 cmets 中所说,我可能会在这里直接使用 list,因为您实际上所做的只是给现有方法加上别名,这通常只会使您的代码更难在从长远来看,因为它需要人们使用它来学习您在原始界面之上的别名界面。

【讨论】:

is_empty 应该返回 not self。当然,这样做可能是个坏主意。它试图使 Python 集合接口看起来像其他语言。 我在is_empty 上的错误,我修正了。至于你的另一点,我同意在这种情况下你可能应该只使用标准列表接口,但是如果你有合法的需要,创建一个子类来在现有类型上实现一个额外的接口是完全合理的。 你如何定义流行音乐? pop(self, item) : self.pop(item)? 您不需要这样做,因为list 已经有一个pop 可以完全按照您的需要工作,无需任何参数。 你真的应该直接使用list 接口,除非你需要为某种家庭作业分配别名方法名称。【参考方案11】:

您的问题是您从列表的开头弹出,而您应该从列表的末尾弹出。堆栈是一种后进先出数据结构,这意味着当您从中弹出某些内容时,该内容将是您最后推送的内容。看看您的推送功能 - 它会将一个项目附加到列表中。这意味着它位于列表的末尾。但是,当您调用 .pop(0) 时,您将删除列表中的第一项,而不是您最后添加的一项。从 .pop(0) 中删除 0 应该可以解决您的问题。

【讨论】:

这不是主要问题。更大的问题是尝试分配给self 感谢您的帮助。【参考方案12】:

分配给self 不会将您的对象变成一个列表(如果是这样,该对象将不再具有您所有的堆栈方法)。分配给self 只会改变一个局部变量。相反,设置一个属性:

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

并使用属性,而不是仅仅使用 self:

def push(self, item):
    self.stack.append(item)

另外,如果你想要一个堆栈,你想要pop() 而不是pop(0)pop(0) 会将您的数据结构变成一个(n 低效)队列。

【讨论】:

以上是关于用 Python 实现堆栈的主要内容,如果未能解决你的问题,请参考以下文章

如何用Python实现堆栈和队列详细讲解

万能的list列表,python中的堆栈队列实现全靠它!

用 Python 在一个矩形中打包气泡图堆栈

Python中的高效堆栈实现

使用两个堆栈 Python 实现一个队列

python列表实现堆栈和队列