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

LeetCode21合并两个有序链表Swift解法dummy节点作用解答

关于合并有序链表代码中dummy节点的作用说明

let dummy = ListNode(0)创建的是链表操作中非常常用的哨兵节点(哑节点),它本身不存储任何有效业务数据,核心作用是简化边界处理逻辑,避免冗余判断,具体作用可以拆成两点:

  • 统一节点拼接逻辑,规避头节点特殊判断
    如果不使用这个占位节点,你在开始循环拼接前必须先单独判断两个链表的首节点,确定合并后链表的头节点,还要额外处理两个输入链表为空、其中一个为空的边界场景,代码会多出很多零散的分支判断,很容易写出空指针bug。有了dummy节点后,所有节点的拼接规则完全统一:循环过程中只需要不断把值更小的节点接在当前遍历指针的next位置即可,不需要单独区分“第一个节点”和“后续节点”的处理逻辑。
  • 作为遍历锚点,方便最终返回结果
    代码中var node = dummy是把遍历指针初始指向这个哨兵节点,整个拼接过程中node不断向后移动,始终指向当前已拼接完成部分的最后一个节点。等全部拼接逻辑跑完,合并后链表的真实起始节点就是dummy.next:
    • 如果两个输入链表全为空,dummy.next为nil,刚好对应空链表的返回结果
    • 如果其中一个链表为空,最后执行node.next = l1 ?? l2拼接完剩余节点后,dummy.next也能正确指向第一个有效节点

补充说明:初始化dummy时传入的参数0没有实际意义,因为这个节点永远不会被包含在最终返回的结果链表里,只是构造ListNode需要传入一个初始值而已,换成-100、100等任意合法节点值都不会影响代码运行结果。

你可以对比下不使用dummy节点的实现,就能明显感受到它的便利性:

// 不使用dummy节点的冗余实现
func mergeTwoLists(l1: ListNode?, _ l2: ListNode?) -> ListNode? {
    // 先单独处理空链表边界
    guard l1 != nil else { return l2 }
    guard l2 != nil else { return l1 }
    
    var l1 = l1, l2 = l2
    var head: ListNode?
    var cur: ListNode?
    
    // 单独确定头节点
    if l1!.val < l2!.val {
        head = l1
        cur = l1
        l1 = l1!.next
    } else {
        head = l2
        cur = l2
        l2 = l2!.next
    }
    
    // 后续循环逻辑和原代码一致
    while l1 != nil && l2 != nil {
        if l1!.val < l2!.val {
            cur?.next = l1
            l1 = l1!.next
        } else {
            cur?.next = l2
            l2 = l2!.next
        }
        cur = cur?.next
    }
    cur?.next = l1 ?? l2
    return head
}

可以看到多了近10行边界和头节点处理代码,出错概率也会高很多。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:09:19