Leetcode中使用的Python链表数据结构让我非常困惑。我不确定这个问题是由Leetcode创建的特定ListNode结构引起的,还是我对Python有一些误解。例如,下面的一段代码很简单并且可以自我解释:
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
def main():
# Instantiate a linked list 1 -> 2 -> 3
a = ListNode(1)
b = ListNode(2)
c = ListNode(3)
a.next = b
b.next = c
print(a) # a is 1 -> 2 -> 3
b.next = None
print(a) # a is 1 -> 2
b = None
print(a) # a is still 1 -> 2, why changing b doesn't change a, but changing b.next changes a???
假设我有一个链表a->b->c.当我设置b.next = None
、a.next.next = None
。然而,让我困惑的是,当我设置b = None
时,a.next
并没有变成None
。操作b
和b.next
有什么区别,为什么它们对a
有不同的影响?
绘制图表有帮助。这是你的链接列表:
[ ]
|
v
[ ]
|
V
[ ]
|
V
None
从框中引出的每个箭头表示该节点的next
属性。
以下是三个变量a
、b
和c
:
[ ] <-- a
|
v
[ ] <-- b
|
V
[ ] <-- c
|
V
None
这些变量中的每一个还指向一个特定的节点。
如果说b.next = None
,则b
引用的节点的next
属性将被修改,如下所示:
[ ] <-- a
|
v
None <-- [ ] <-- b
[ ] <-- c
|
V
None
这将修改列表的结构。不过,如果您只是将b
本身设置为不同的值,则会发生以下情况:
[ ] <-- a
|
v
None <-- [ ] b --> None
[ ] <-- c
|
V
None
您更改了b
,但b
用来指向的节点保持原样。请注意,这类似于c
节点在设置b.next = None
之后仍然存在的情况。
Python没有双指针,例如**x
b.next = c
print(a) # a is 1 -> 2 -> 3
b.next = None
例如,在上面,它并不意味着c is None
当a.next
为b
时,如果更改a.next.next
,则实际上是在更改b.next
但如果将a.next
更改为None
,则不会将b
设置为None
编辑:
同样,当您设置b = None
但a.next
仍指向ListNode(2)
时
a
是对ListNode(1)
的引用。对ListNode(2)
有两个引用:一个存储在ListNode(1)
中,被引用为a.next
,另一个在b
中。
把这些参考文献想象成箭头。
当您指定b = None
时,只需将箭头从b
删除到ListNode(2)
,并将其替换为从b
到None
的箭头。这对从ListNode(1)
到ListNode(2)
的箭头没有影响。
如果您改为对ListNode(3)
进行更改,那么该更改将从所有三个引用中可见:a.next.next
、b.next
和c
。
注意,像b.next = ...
这样的分配与b = ...
非常不同。后者是一个";真";赋值,而前者是像setattr(b, 'next', ...)
这样的函数调用的特殊语法。它在适当的位置修改一些对象(特别是它的一个属性的值(,而不仅仅是使名称指向其他对象。