请求解释LeetCode合并两个有序链表的JavaScript实现代码
合并两个有序链表的JavaScript代码详解
这段代码用于解决LeetCode「合并两个有序链表」问题,先明确:输入是两个单链表(你最后定义的数组直接传入会报错,LeetCode测试用例会传符合ListNode结构的链表),输出是合并后的有序链表。
先理解链表节点结构
代码开头的ListNode是单链表的基础节点定义:
function ListNode(val, next) { this.val = (val===undefined ? 0 : val) this.next = (next===undefined ? null : next) }
每个节点包含:
val:当前节点存储的数值next:指向下一个节点的指针,null代表链表的末尾
代码逐段解析
1. 初始化变量
let dummyHead = new ListNode(); let tail = dummyHead; let curr1 = list1; let curr2 = list2;
dummyHead:哑节点,用来简化边界处理(比如两个输入链表都为空的情况),本身不存储有效数据tail:始终指向当前合并完成的链表的最后一个节点,初始指向哑节点curr1/curr2:遍历list1和list2的指针,初始分别指向两个输入链表的头节点
2. 核心合并循环
while(curr1 !== null && curr2 !== null){ if(curr1.val < curr2.val){ tail.next = curr1; curr1 = curr1.next; } else{ tail.next = curr2; curr2 = curr2.next; } tail = tail.next; }
这个循环的运行条件是两个输入链表都未遍历完成(curr1和curr2都不为null):
- 每次比较
curr1和curr2的数值,将值更小的节点接到合并链表的尾部(tail.next) - 把被选中的链表指针(
curr1或curr2)向后移动一位,继续遍历 - 最后将
tail也向后移动一位,保持它指向合并链表的末尾
以你给出的测试用例为例(转成链表后):
- 首次比较1和1,选择
list2的节点,tail.next指向该节点,curr2移到3,tail移到这个1节点 - 第二次比较1和3,选择
list1的节点,重复上述操作,直到其中一个链表遍历完毕
3. 循环结束后的关键逻辑(你重点关注的部分)
if(curr1 !== null){ tail.next = curr1; } if(curr2 !== null){ tail.next = curr2; }
循环终止的原因是至少有一个输入链表已经遍历完成(curr1或curr2为null):
- 因为输入的两个链表本身就是有序的,剩下未遍历的链表的所有节点,数值必然大于等于合并链表最后一个节点的数值
- 因此不需要再逐个比较,直接把剩余的整个链表接到合并链表的尾部即可
比如你的测试用例,循环结束时可能其中一个指针已经指向null,另一个还指向剩余的节点(比如最后一个4),直接把这个剩余链表接到tail.next,就能得到完整的有序合并链表。
4. 返回最终结果
return dummyHead.next;
dummyHead是我们初始化的占位节点,真正的合并链表从它的next指针开始,因此返回这个值。
测试补充
你最后定义的数组无法直接传入函数,需要先转成链表结构,可使用以下辅助函数:
function arrayToList(arr) { let dummy = new ListNode(); let tail = dummy; for(const num of arr) { tail.next = new ListNode(num); tail = tail.next; } return dummy.next; } // 测试调用 let list1 = arrayToList([1,2,4]); let list2 = arrayToList([1,3,4]); mergeTwoLists(list1, list2); // 得到预期的有序链表
内容的提问来源于stack exchange,提问作者Jeffrey
相关产品推荐
相关产品推荐

