You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python3合并有序链表题中dummy节点变化原因及cur指针关系解析

先搞懂两个最基础的前提

所有你觉得“反直觉”的指针现象,本质都是没搞懂这两个规则:

  • Python里的变量不是存储对象的盒子,是贴在对象上的标签。写a = b不是把b里的东西复制给a,是给b指向的内存对象,多贴一张叫a的标签,两个标签指向完全同一个实体。
  • 链表节点是独立的内存对象,只有两个属性:存数值的val,存下一个节点引用的next。修改某个节点的next属性,所有指向这个节点的标签,读取到的next都会同步变化;但如果只是把某个标签从一个节点撕下来贴到另一个节点上,原来的节点不会有任何改动。
逐行对应你的观察结果解释

初始状态

代码第一行cur = dummy = ListNode()做的事非常简单:

  1. 内存里新建一个值为0、next为None的初始节点
  2. 给这个节点贴两个标签,一个叫dummy,一个叫cur
    此时两个标签完全指向同一个节点,没有任何区别。

解释第一个现象:cur.next = xxx改了dummy,cur = xxx不改

你观察到的这个现象,和“同步”没有任何关系:

  • 第一次迭代进入else块时,cur标签还和dummy一起贴在初始0值节点上。执行cur.next = list2,本质是直接修改0值节点的next属性,让它指向list2当前对应的1值节点。dummy本来就贴在0值节点上,你改了0值节点的属性,它当然能看到变化。
  • 紧接着执行list2, cur = list2.next, list2:这是Python的并行赋值,先计算等号右侧的两个值——list2.next是3值节点,当前list2指向1值节点,再把两个标签重定向:list2标签贴到3值节点上,cur标签从原来的0值节点撕下来,贴到1值节点上。
    注意这个过程中dummy标签自始至终都贴在0值节点上没动,你只是移动了cur标签的位置,0值节点本身没有任何改动,dummy自然不会变。

解释第二个现象:第三个块里改cur.next变成了改dummy.next.next

进入第三个代码块时,cur标签已经不在0值节点上了——它现在贴在刚才那个来自list2的1值节点上,而这个1值节点正好是dummy.next指向的节点。
此时执行cur.next = list1,修改的已经不是0值节点的next,而是这个1值节点的next属性。从dummy的视角顺着链路看:
dummy → 0值节点 → next是1值节点(来自list2) → next现在被改成了list1的1值节点
对应的就是dummy.next.next被赋值,自然不会直接改动dummy直接关联的next属性。

用串珠子的类比一秒搞懂整体逻辑

你可以把整个合并过程类比成串珠子,完全不用记什么指针规则:

  • dummy是你钉在桌子上的固定绳头,从算法开始到结束永远不动,最后你只要提这个绳头,就能把整串合并好的珠子拎起来,所以最后返回dummy.next就行。
  • cur是你串珠子时捏在手里的位置,最开始你捏着绳头(和dummy指向同一个位置)。
  • 每次循环你从两个链表的表头挑一个值更小的珠子,系在你当前捏着的位置后面(也就是执行cur.next = 选中的节点),系完之后你的手往后挪一位,捏到刚系上的这个新珠子上(也就是执行cur = cur.next),准备串下一个。
  • 你手(cur)往后挪的时候,钉在桌上的绳头(dummy)当然不会动;你在当前捏的珠子后面系新珠子,改的是手里这个珠子的尾部,不是绳头的尾部,串的珠子越多,你手离绳头越远,修改next的位置就越往链路深处走,对应到dummy视角就是dummy.next、dummy.next.next、dummy.next.next.next依次被赋值。
你贴的代码有个逻辑错误

你现在把剩余链表拼接的逻辑(第三个块)写在了while循环内部,第一次循环就会把剩下的整条链表直接接上,完全不符合逐次比较合并的逻辑,这也会干扰你观察打印结果。正确的代码结构应该把剩余拼接放到循环结束之后:

def mergeTwoLists(list1, list2):
    cur = dummy = ListNode()
    while list1 and list2:
        if list1.val < list2.val:
            cur.next = list1
            list1 = list1.next
        else:
            cur.next = list2
            list2 = list2.next
        cur = cur.next  # 统一移动cur,不用写在分支赋值里
    # 循环退出时至少一个链表已遍历完,直接把剩余段接上即可
    cur.next = list1 if list1 else list2
    return dummy.next

内容的提问来源于stack exchange,提问作者srv_77

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.30 18:33:34