分隔链表算法详解:双虚拟头节点拆解合并法
题目解析:读懂分隔链表的核心要求
力扣86题「分隔链表」的核心需求十分清晰:
给定一个单链表和一个数值x,请将链表划分为两个部分,所有小于x的节点排在链表前半部分,所有大于或等于x的节点排在链表后半部分。
⚠️ 注意:划分后无需改变原链表中节点的相对顺序,仅完成区域分隔即可。
举个例子:
若链表为1→4→3→2→5→2,给定x=3,则分隔后的链表应为1→2→2→4→3→5。
其中小于3的节点:1、2、2;大于等于3的节点:4、3、5,严格遵循原链表中的相对顺序。
这道题的解题关键在于不额外开辟大量空间,仅通过指针操作完成节点的重新拼接,时间复杂度需控制在O(n)(仅遍历原链表一次),空间复杂度为O(1)(仅使用常数个指针)。
算法原理:双虚拟头节点的巧思
为什么选择双虚拟头节点?
单链表的痛点在于头节点可能被修改,且对空链表、单节点链表的处理需要额外的边界判断。而虚拟头节点(哑节点) 是解决链表头节点问题的'万能钥匙',它是一个不存储实际值的节点,指向真正的头节点,能让我们的指针操作统一化,无需单独处理边界情况。
分隔链表的核心算法原理:
- 定义两个虚拟头节点,分别对应小值链表(存储小于
x的节点)和大值链表(存储大于等于x的节点); - 定义两个尾指针,分别指向小值链表和大值链表的末尾,用于快速拼接新节点;
- 遍历原链表,根据节点值的大小,将节点依次拼接到小值链表或大值链表的末尾;
- 遍历完成后,将小值链表的尾节点指向大值链表的真实头节点,完成两个链表的合并;
- 最终返回小值链表的真实头节点,即为分隔后的结果链表。
步骤图解:直观理解算法执行过程
为了让大家更清晰地看到每一步的操作,我们以链表1→4→3→2→5→2、x=3为例,用图解展示双链表拆解合并的全过程(🔵代表小值链表,🟡代表大值链表)。
步骤1:初始化虚拟头节点和尾指针
- 小值链表虚拟头节点:
dummySmall,尾指针pSmall(初始指向dummySmall) - 大值链表虚拟头节点:
dummyLarge,尾指针pLarge(初始指向dummyLarge) - 遍历指针
p(初始指向原链表头节点)
dummySmall → null | dummyLarge → null ↑ | ↑ pSmall | pLarge 原链表:1 → 4 → 3 → 2 → 5 → 2 ↑ p


