[英]Why is the head getting changed when changing a different node in a linked list?
当我们将cur
替换为cur.next
( else
语句)后cur
变化时,head 是如何变化的?
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]:
cur=head
while cur.val and cur.next:
if cur.val==cur.next.val:
cur.next=cur.next.next
else:
cur=cur.next
print(cur)
return head
我知道当我们执行cur=head
时,我们正在创建一个引用,因此对 head 所做的任何更改都将被更新(因为cur
和head
具有相同的 id)但是当输入else
时, cur
被更改并且cur
和head
不t 不再有相同的 id(在else
中只有cur
改变了)但是当我们回到if
子句时,对cur
的任何修改也会影响 head。 怎么会发生这种情况,他们甚至没有相同的 ID?
首先,代码在while
条件下不应该有cur.val
。 当cur.val
为 0 时例外是没有意义的。
现在的问题是: head
不一定会改变:只有当它具有重复值时它才会发生变异。 无论它本身是否有重复项,如果列表中还有重复项,则head
引用的链确实会发生变化。 所以你可以将其解释为head
被改变,但这只是“远程”。
它可能有助于想象它。 假设我们有一个包含 4 个节点的链表,它们的值为 1、2、2 和 3。存在重复项,因此生成的列表中应该省略一个节点。
这是在循环开始之前执行cur=head
时的状态:
head cur
│ │
┌─┴────┴────┐ ┌───────────┐ ┌───────────┐ ┌───────────┐
│ val: 1 │ │ val: 2 │ │ val: 2 │ │ val: 3 │
│ next: ─────────┤ next: ─────────┤ next: ─────────┤ next: None│
└───────────┘ └───────────┘ └───────────┘ └───────────┘
然后在循环中,将 1 与 2 进行比较,因此我们进入else
块,并为cur
分配另一个引用,...位于cur.next
的引用(恰好也是head.next
)。 因此,在该分配之后, cur
将引用与head.next
相同的内容:
head cur
│ │
┌─┴─────────┐ ┌───┴───────┐ ┌───────────┐ ┌───────────┐
│ val: 1 │ │ val: 2 │ │ val: 2 │ │ val: 3 │
│ next: ─────────┤ next: ─────────┤ next: ─────────┤ next: None│
└───────────┘ └───────────┘ └───────────┘ └───────────┘
在第二次迭代中, if
条件为真,因此发生突变(即,属性被分配给): cur.next = cur.next.next
。 右边的表达式是对我们列表中最后一个节点的引用, cur
节点被变异为使用其next
属性引用它:
head cur
│ │ ┌───────────────┐
┌─┴─────────┐ ┌───┴───────┐ │ ┌───────────┐ │ ┌───────────┐
│ val: 1 │ │ val: 2 │ │ │ val: 2 │ └──┤ val: 3 │
│ next: ─────────┤ next: ───────┘ │ next: ─────────┤ next: None│
└───────────┘ └───────────┘ └───────────┘ └───────────┘
此时,值为 2 的第二个节点已分离——不再有对它的引用,因此可以对其进行垃圾回收。 由于我们无法再达到它,因此在没有它的情况下描绘这种状态没有区别:
head cur
│ │
┌─┴─────────┐ ┌───┴───────┐ ┌───────────┐
│ val: 1 │ │ val: 2 │ │ val: 3 │
│ next: ─────────┤ next: ─────────┤ next: None│
└───────────┘ └───────────┘ └───────────┘
这个突变是针对cur
引用的节点完成的,但是因为head.next
也引用了那个节点,所以这个突变可以通过head
“看到”(通过跟随next
链)。 它不是head
属性的直接突变,但可以看到进一步的变化。
在下一次迭代中, cur
处的值与 3 进行比较,这意味着我们进入if
块, cur = cur.next
使cur
引用最后一个节点。 请注意,此语句是对名称的赋值——它不会改变任何对象。 要改变一个对象,必须分配给一个属性。
无论如何,我们进入这种状态:
head cur
│ │
┌─┴─────────┐ ┌───────────┐ ┌───┴───────┐
│ val: 1 │ │ val: 2 │ │ val: 3 │
│ next: ─────────┤ next: ─────────┤ next: None│
└───────────┘ └───────────┘ └───────────┘
现在while
条件为假, head
返回给调用者,而名称cur
现在被丢弃。 所以调用者看到这个:
(returned)
│
┌─┴─────────┐ ┌───────────┐ ┌───────────┐
│ val: 1 │ │ val: 2 │ │ val: 3 │
│ next: ─────────┤ next: ─────────┤ next: None│
└───────────┘ └───────────┘ └───────────┘
我希望这能澄清它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.