链表反转时不同赋值方式导致结果差异的原因解析
链表反转中不同赋值方式的差异问题
我在尝试反转链表时发现,不同的赋值方式会导致结果不同,具体情况如下:
from typing import Optional class ListNode: def __init__(self, val=0, next: Optional["ListNode"] = None): self.val = val self.next = next # 使用解包赋值,结果符合预期 nodes = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5))))) rev = None while nodes is not None: rev, rev.next, nodes = nodes, rev, nodes.next # rev = [5, 4, 3, 2, 1] # 但逐个赋值时,结果不符合预期 cnt = 0 nodes = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5))))) rev = None while nodes is not None: if cnt > 10: break rev = nodes rev.next = rev nodes = nodes.next cnt += 1 # rev = [1, 1, 1, 1, 1...] 出现循环引用导致无限循环!
我的运行环境为Python 3.10.7,请问为何会出现这样的差异?
原因解析
核心差异在于Python中解包赋值与逐个赋值的执行逻辑完全不同:
1. 解包赋值的执行逻辑
rev, rev.next, nodes = nodes, rev, nodes.next 这行代码遵循「先计算所有右侧值,再批量赋值」的规则:
- 第一步:一次性获取当前
nodes的引用(记为A)、当前rev的引用(记为B)、当前nodes.next的引用(记为C),这三个值会被临时缓存,不受后续赋值操作影响 - 第二步:依次将A赋值给
rev,B赋值给A.next(也就是新的rev.next),C赋值给nodes
整个过程中,修改rev.next时操作的是原nodes节点的next属性,而此时nodes还未被更新,不会破坏原链表的后续节点引用,因此能正确完成反转。
2. 逐个赋值的执行逻辑
而逐个赋值的代码执行顺序是「赋值一个,生效一个」:
rev = nodes rev.next = rev nodes = nodes.next
- 第一步:
rev = nodes让rev指向当前nodes节点(比如第一次循环是节点1) - 第二步:
rev.next = rev直接将这个节点的next指向自身,制造了循环引用 - 第三步:
nodes = nodes.next此时nodes.next已经变成了节点1自己,所以nodes仍然指向节点1,下一次循环重复同样操作,最终整个链表变成循环链表。
如果要修正逐个赋值的写法,需要先缓存原nodes.next的引用,避免修改next属性后丢失后续节点:
cnt = 0 nodes = ListNode(1, ListNode(2, ListNode(3, ListNode(4, ListNode(5))))) rev = None while nodes is not None: if cnt > 10: break next_node = nodes.next # 先保存下一个节点的引用 nodes.next = rev # 修改当前节点的next指向rev rev = nodes # 更新rev为当前节点 nodes = next_node # 让nodes指向之前保存的下一个节点 cnt += 1 # rev = [5,4,3,2,1] 结果正确
内容的提问来源于stack exchange,提问作者kama-meshi
相关产品推荐
相关产品推荐

