

js
/**
* 两两交换链表中的节点
* @param {ListNode} head - 链表的头节点
* @returns {ListNode} - 交换后的链表头节点
*/
var swapPairs = function (head) {
// 1. 创建哨兵(虚拟)节点,值为0,next指向原链表头节点
// 作用:统一处理链表头节点交换的边界情况,避免单独判断头节点
const dummy = new ListNode(0, head)
// 2. 初始化遍历指针node0,指向哨兵节点(作为每一轮交换的前驱节点)
let node0 = dummy
// 3. 初始化遍历指针node1,指向原链表的第一个节点(每一轮交换的第一个节点)
let node1 = head
// 4. 循环条件:至少存在两个待交换的节点(node1和node1.next都不为空)
// 如果node1为空(链表长度为0)或node1.next为空(链表长度为1),则无需交换
while (node1 && node1.next) {
// 5. 暂存node1的下一个节点(本轮要交换的第二个节点)
const node2 = node1.next
// 6. 暂存node2的下一个节点(本轮交换后,node1需要指向的节点)
const node3 = node2.next
// 7. 核心交换逻辑:调整指针指向
node0.next = node2 // 让前驱节点node0指向node2(原第二个节点)
node2.next = node1 // 让node2指向node1(原第一个节点),完成两两交换
node1.next = node3 // 让node1指向node3,连接到未交换的后续链表
// 8. 移动指针,准备下一轮交换
node0 = node1 // node0更新为当前的node1(本轮交换后的第二个节点)
node1 = node3 // node1更新为node3(下一轮交换的第一个节点)
}
// 9. 返回哨兵节点的next,即交换后的链表头节点
// 因为哨兵节点本身不存储有效数据,只是辅助作用
return dummy.next
}