LeetCode链表题dummy节点用法疑惑:以第21题合并有序链表为例
解答
疑问1:dummy节点的作用,为什么不能直接初始化res后返回res.next
dummy节点也叫哨兵节点,核心作用是固定新链表的头节点位置,避免遍历过程中丢失头节点地址。
如果你不使用dummy,只单独定义res = ListNode(None),后续遍历过程中会执行res = res.next操作让res不断向链表尾部移动,遍历结束后res已经指向新链表的最后一个节点,此时返回res.next只会得到空值,完全找不到新链表的起始位置。你如果单独再定义一个变量存初始的res节点,那这个变量本质上就是dummy节点,和现在的写法没有区别。
疑问2:为什么全程没有修改dummy,最终返回dummy.next是有效结果
这个困惑的核心是混淆了Python中不可变对象赋值和可变对象引用的差异:
- 你举的整数示例属于不可变对象操作:
a = 3是把不可变的整数3赋值给a,b = a是把3的值复制给b,后续b = b + 2是给b重新赋值为新的整数5,两个变量指向完全不同的内存地址,自然不会互相影响。 - 而
ListNode的实例是可变对象:dummy = ListNode(None)会在内存中创建一个节点对象,res = dummy是让res和dummy两个变量指向同一个内存地址的同一个节点对象,没有发生任何值复制。 - 循环中第一次执行
res.next = l1时,修改的是这个公共节点对象的next属性,dummy作为指向同一个对象的变量,自然能感知到这个修改。后续执行res = res.next才是给res变量重新赋值,让它指向新的节点,这一步才和你整数示例中b = b + 2的逻辑一致,不会修改dummy的指向,dummy始终停留在最开头的哨兵节点位置。 - 遍历结束后,dummy的next属性已经指向新链表的第一个有效节点,而res已经移动到新链表的尾部,返回
res.next只能得到空值,只有dummy.next才是完整新链表的头节点。
你可以运行下面的测试代码验证逻辑:
class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next dummy = ListNode(None) res = dummy # 修改公共节点的next属性,dummy同步变化 res.next = ListNode(1) print(dummy.next.val) # 输出 1 # 重新赋值res的指向,dummy不受影响 res = res.next res.next = ListNode(2) print(dummy.next.next.val) # 输出 2 # 此时res已移动到第二个节点,dummy仍在初始位置 print(res.val) # 输出 1 print(dummy.val) # 输出 None
内容的提问来源于stack exchange,提问作者Cairo
相关产品推荐
相关产品推荐

