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

LeetCode合并两个有序链表为何用dummy head且给next节点赋值?

合并两个有序链表代码疑问解答

问题背景

这是一道LeetCode题目,核心要求是合并两个有序链表,参考题解代码时存在两点核心困惑:

  • 代码实现中为什么要使用dummy head(虚拟头节点)?
  • 为什么赋值操作是给next节点赋值,而非直接给当前节点赋值?

自行梳理逻辑、添加打印语句调试后仍有疑问:为什么代码写的是node.next = new ListNode(list1.val);,替换成node = new ListNode(list1.val);运行就会返回空链表,不清楚背后的实现原理。

涉及的参考代码如下:

var mergeTwoLists = function (list1, list2) {
  const head = new ListNode(0);
  let node = head;
  while (list1 !== null || list2 !== null) {
    if (list2 === null || (list1 !== null && list1.val <= list2.val)) {
      node.next = new ListNode(list1.val);
      list1 = list1.next;
    } else {
      node.next = new ListNode(list2.val);
      list2 = list2.next;
    }
    node = node.next;
  }
  return head.next;
};

具体解答

为什么要用虚拟头节点

本质是为了消掉头节点的特殊边界判断。
如果不用虚拟头,最开始结果链表是空的,你第一次加节点的时候得单独给结果链表的头指针赋值,还要额外处理两个输入链表其中一个为空的场景,代码会多写不少分支。虚拟头就是个提前建好的无意义占位节点,所有真实的业务节点都按统一逻辑接在它后面,等全部拼接完成,直接返回head.next就是真实的结果链表头,全程不需要单独处理“结果链表为空”的特殊情况,代码逻辑能保持统一,少出bug。

为什么要给node.next赋值,不能直接给node赋值

这里的node本质是个遍历游标,永远指向当前结果链表的最后一个节点,作用是标记下一个新节点要接的位置。

  • 如果你写node = new ListNode(list1.val),只是把node这个变量本身的引用改成了新节点,之前已经拼好的链表和这个新节点之间没有任何指针关联,相当于你拼到一半直接把游标从原链表上拔下来,插到了一个孤立的新节点上,最开始存的head指针从头到尾都没接上任何有效节点,最后返回head.next当然是空。
  • 写node.next = new ListNode(xxx)才是真的把新节点挂到了当前结果链表的尾部,维持住了整个链表的指针关联。挂完新节点之后再执行node = node.next,把游标移到新的尾部节点,准备接下一个节点,整个拼接过程链表的链接关系一直是连续的,不会断。

打个比方:串珠子的时候,node就是你捏着串绳尾端的手,给node.next赋值相当于把新珠子系在你手捏着的绳尾,再把手挪到新珠子末尾准备串下一颗;如果直接给node赋值,相当于你直接松开绳子去抓新珠子,之前串好的珠子全留在原地,和你新抓的珠子根本连不上,最后拎着绳头(也就是head)的时候自然什么都没串上。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:27:41