繁体   English   中英

为什么在更改链表中的不同节点时头部会发生变化?

[英]Why is the head getting changed when changing a different node in a linked list?

当我们将cur替换为cur.nextelse语句)后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 所做的任何更改都将被更新(因为curhead具有相同的 id)但是当输入else时, cur被更改并且curhead不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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM