我有一个链表,我希望将其作为队列实现。我已经发现它有效但我对这个特定部分的工作原理有疑问。这是代码:
class LinkedQueue:
class _Node:
def __init__(self, element, next):
self._element = element
self._next = next
def __init__(self):
self._head = None
self._tail = None
self._size = 0
def enqueue(self, e):
newest = self._Node(e, None)
if self.is_empty():
self._head = newest
else:
self._tail._next = newest
self._tail = newest
self._size += 1
如果队列为空并且我入队,则入队中的第一个条件为真并且被触发并且最新被分配给self._head。但是,当我添加另一个元素时,会触发else块,并且最新分配self._tail._next。显然,这会改变_head的_next变量。但是,在分配第三个元素时,_head的_next变量不会更改。为什么会这样?另外,最近不应该_tail改变,因此_next变量被新分配的None覆盖?
代码完全有效,我理解链接列表逻辑,但我不明白为什么这个特定代码有效。
答案 0 :(得分:1)
你问:
self._tail._next
已分配newest
。显然,这改变了_next
的{{1}}变量。
是的,因为当时_head
和_tail
是同一对象的两个名称。
当然,分配给_head
与分配给_tail._next
会产生完全相同的效果 - 怎么可能不会,因为_head._next
和_tail
指的是非常相同的对象?
让我们看看它们是如何引用同一个对象的!当_head
分支执行时,您执行if
;然后在self._head = newest
if/else
之后无条件地执行。在Python中,赋值总是通过引用 - 赋值(对于名称[*])本身永远不会隐式地复制。
(将分配给一个列表是一个非常不同的操作,从而这个迂腐的括号 - 但是现在让我们忘记它,因为你没有处理对切片的赋值: - )。
但是,在分配第三个元素时,
self._tail = newest
变量为_next
没有改变。为什么会这样?
因为在那个时候_head
和_tail
是同一个对象的两个名称并不是真的:它们就是不同对象的名称。
那是因为第二次你已经分配了不同的东西(_head
)到newest
- 但是没有给self._tail
分配任何新东西,因此仍然指的是上一个对象... self._head
不再提及。
此外,
覆盖_tail
不应更改_tail
,因此newest
变量被新分配的无?
_next
确实被重新约束("更改"是一个非常含糊的术语! - )来引用与self._tail
相同的对象,所以如果你打印{{1}那时(在newest
方法的最后),您确实会将其视为self._tail._next
。但是,之前的enqueue
分配会影响当时提到的None
的{{1}}属性 (之前 { {1}}!) - 具有self._tail._next
新分配的节点立即成为列表中的倒数第二个节点。
答案 1 :(得分:0)