在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有垃圾收集功能。您可以从中找到接口。