在Python 2.7中使用自由列表功能实现堆栈

在Python 2.7中使用自由列表功能实现堆栈,python,python-2.7,stack,Python,Python 2.7,Stack,设计一个具有自由列表特性的堆栈(即,节点弹出后,其空间可通过未来的推送操作重用,并保留在自由列表中)。代码被简化了,在某些方面没有意义,我只是使用下面的代码来展示自由列表堆栈(作为一个原型)的一般思想 我的问题是关于如何设计pop操作。我的困惑是,对节点的引用是在pop操作之后返回的,例如,在我的代码中有node1=stack.pop(),对节点的引用可能会被调用pop的客户机使用,相同的节点引用会在自由列表中回收,并可能会被其他push操作使用,如何解决这类冲突,以及如何设计具有堆栈、链表或队

设计一个具有自由列表特性的堆栈(即,节点弹出后,其空间可通过未来的推送操作重用,并保留在自由列表中)。代码被简化了,在某些方面没有意义,我只是使用下面的代码来展示自由列表堆栈(作为一个原型)的一般思想

我的问题是关于如何设计
pop
操作。我的困惑是,对节点的引用是在
pop
操作之后返回的,例如,在我的代码中有
node1=stack.pop()
,对节点的引用可能会被调用
pop
的客户机使用,相同的节点引用会在自由列表中回收,并可能会被其他
push
操作使用,如何解决这类冲突,以及如何设计具有堆栈、链表或队列的自由列表功能

MAXSIZE = 100
freeListHead = None

class StackNode:
    def __init__(self, value, nextNode):
        self.value = value
        self.nextNode = nextNode
class Stack:
    def __init__(self):
        self.top = None
        self.size = 0
    def peek(self):
        # return StackNode
        return self.top
    def push(self, value):
        global freeListHead
        if self.size >= MAXSIZE:
            raise Exception('stack full')
        node = freeListHead
        node.value = value
        freeListHead = node.nextNode
        node.nextNode = self.top
        self.top = node
        self.size += 1
    def pop(self):
        if self.size == 0:
            return None
        node = self.top
        self.top = self.top.nextNode
        self.size -= 1
        return node

if __name__ == "__main__":
    # initialization for nodes and link them to be a free list
    nodes = [StackNode(-1, None) for i in range(MAXSIZE)]
    freeListHead = nodes[0]
    for i in range(0, len(nodes)-1):
        nodes[i].nextNode = nodes[i+1]
    stack = Stack()
    stack.push(1)
    stack.push(50)
    stack.push(100)
    stack.push(200)
    print stack.peek().value
    node1 = stack.pop()
    print node1.value
    print stack.peek().value

您可以通过返回给定给
push
值来简化代码,而不是保存该值的
StackNode
。由于可以在返回结果之前在
pop
中将
node.value
设置为
None
,因此不需要考虑内存消耗。下面是一个简单的例子,说明这在实践中是如何起作用的:

class Node:
    def __init__(self):
        self.nextNode = self.value = None

class Stack:
    def __init__(self, maxSize):
        self.maxSize = maxSize
        self.size = 0
        self.top = self.free = None

    def push(self, value):
        if self.size == self.maxSize:
            raise Exception('Stack full')

        if self.free:
            node = self.free
            self.free = node.next
        else:
            node = Node()

        node.value = value
        node.nextNode = self.top
        self.top = node
        self.size += 1

    def pop(self):
        if not self.top:
            raise Exception('Stack empty');
        node = self.top
        self.top = node.nextNode
        node.nextNode = self.free
        self.free = node
        self.size -= 1
        result = node.value
        node.value = None

        return result

stack = Stack(3)
for i in range(3):
    stack.push(list(range(i + 1)))

while stack.size:
    print(stack.pop())
输出:

[0, 1, 2]
[0, 1]
[0]

当您的
push
接受值而不是节点时,为什么要从
pop
返回节点?对我来说,
pop
返回与
push
@niemmi完全相同的内容会更有意义,捕捉得不错。这是一个很好的选择。如果我希望
push
pop
处理
StackNode
而不是
int
,是否有解决方案?已经有了,请参见您的
push
实现,它接受一个参数,但不关心类型。同样,您可以使用
pop
返回
node.value
,无论类型如何。感谢@niemmi,我的意思是如果我需要从
pop
返回
StackNode
(出于封装的目的,因为
StackNode
可以包装除
int
之外的许多其他内容),有什么建议可以避免冲突吗?请这样想:除了访问属性(如
node.value
)之外,您还打算如何处理返回的
node
?谢谢,请投赞成票,但如果您
node.value=None
,我会担心,那么空闲列表就没有用了,因为弹出节点使用的内存空间不能被重用。@LinMa我不确定我在这里跟不上你,因为弹出节点在
push
方法中被重用。假设堆栈将存储从
pop
返回的值。那么下次调用
push
时,堆栈如何知道客户机是否已将返回的
值存储在某个位置,并将在以后使用它,或者是否可以通过堆栈以某种方式重用它?谢谢,并投票支持答复,实际上,我使用free list的目的是为了节省创建新的
StackNode
对象的时间/内存,并重新使用
value
消耗的内存,您的代码可以实现目标(尤其是后者)?@LinMa这很重要,因为Python使用,而只要引用对象,GC就无法收集对象。因此,在
pop
中将
node.value
设置为
None
,允许GC在调用者处理完对象后立即释放该对象。@LinMa:是的,CPython有垃圾收集功能。您可以从中找到接口。