链表——两两交换链表中的节点

给你一个链表,两两交换其中相邻的节点,并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题(即,只能进行节点交换)

题目要求

  • 两两交换相邻节点:1->2->3->4 → 2->1->4->3
  • 不能改节点里的值,只能改指针指向
  • 必须返回新头结点

核心思路:

  1. 虚拟头节点dummy(否则交换第一个节点时必崩)

  2. 每次处理3个指针

  • prev:要交换的两个节点的前一个
  • first:第一个节点
  • second:第二个节点
  1. 三步交换指针(顺序绝对不能错

  2. prev后移,继续下一组

完整代码实现如下:

struct ListNode {

int val;
ListNode *next;
ListNode() : val(0), next(nullptr) {}
ListNode(int x) : val(x), next(nullptr) {}
ListNode(int x, ListNode *next) : val(x, next) {}
};

class Solution {
public:
ListNode* swapPairs(ListNode* head) {

// 虚拟头节点:解决交换头节点的问题
ListNode* dummy = new ListNode(0);
dummy->next = head;

ListNode* prev = dummy;

// 必须有两个节点才能交换
while (prev->next != nullptr && prev->next->next != nullptr) {
ListNode* first = prev->next;
ListNode* second = first->next;

// ====================== 核心三步交换 ======================
first->next = second->next; // 1 指向 3
second->next = first; // 2 指向 1
prev->next = second; // 前驱指向 2(新头)
// ==========================================================

// 前驱前移,准备下一组交换
prev = first;
}

return dummy->next;
}
};

最关键:为什么这三步顺序不能乱?

以prev->q->2->3举例:

1.first->next = second->next
意义:1指向3
目的:先把后面链保住,不然会断链

2.second->next = first
意义:2 指向 1
完成反转

3.prev->next = second
意义:前面的链接到 2
让 2 变成这一组的头

三步顺序错一个,直接链表断裂 / 死循环!

为什么必须用 dummy?
因为:
两两交换一定会改变整个链表的头结点!
原头是 1,交换后变成 2。
没有 dummy,你无法保存新头,也无法交换第一组节点。
有了dummy 永远站在最前面,不管第一组怎么交换,dummy->next 永远是最新的头!

dummy 就是为了:
让第一组节点也有前驱,和后面所有组逻辑完全统一,不用特判。

循环条件为什么是这样?
while (prev->next && prev->next->next)
意思:必须还有至少两个节点,才需要交换。
只剩一个节点或空,停止。

复杂度

  • 时间:O(n) 一遍遍历
  • 空间:**O(1) **仅用指针
posted @ 2026-04-08 16:43  ZealousMclaren  阅读(858)  评论(0)    收藏  举报