🧠 通过修改 next 指针方向,将链表从「顺序结构」重排为「逆序结构」

一句话结论:
👉 反转链表的本质不是换值,而是 改变指针指向

核心三步曲:

  1. 留后路:next = curr.next (防止链表断裂)
  2. 改指向:curr.next = prev (核心反转)
  3. 同推进:prev = curr; curr = next (指针后移)

⚠️ 结束时:curr 是 null,新头节点是 prev

⭐ 模板

  1. 初始化

    //prev:始终指向「已经反转完成的部分」
    ListNode prev = null; (已反转部分的头(新链表))

    //curr:始终指向「下一步要处理的节点」
    ListNode curr = head; (待反转部分的头(原链表))

  2. 链表处理(控制 curr 主动向后推进)

    while (curr != null) {

    // 1. 留后路:保存下一个节点
    ListNode next = curr.next;

    // 2. 改指向:执行反转(核心操作)
    curr.next = prev;

    // 3. 同推进:更新两个指针
    prev = curr;
    curr = next;

}

  1. 返回值
    return prev;

Notice

  1. 🛡️ 链表通用防御模板 (Edge Case Guard)

🚀【防御区】:处理空链表、单节点、或无效操作

  1. 如果链表为空,或者只有一个节点(通常不需要操作),直接返回

if(head == null || head.next == null) return head;

  1. (可选) 如果是区间反转类题目:区间长度为 0,无需反转

if (left == right) return head;

  1. 循环不变量要成立

在每一轮 while 开始前,必须满足:

prev 指向「已经反转好的链表头」

curr 指向「尚未反转的链表头」

  1. 判断是否需要四指针的核心问题:

👉 反转完成后,这一段链表是否还需要接回原链表?

🔹 场景 1:需要接回原链表时 (四指针定位 + 两指针反转)

指针 作用
pre 反转区间前一个节点
start 区间第一个节点(反转后会变尾)
end 区间最后一个节点
next 区间后一个节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

1. 反转开始前 (定位)

pre start end next
| | | |
... --> O ------> O --> ... --> O -> O ------> O --> ...
(前驱) (反转头) (反转尾) (后继)

2. 反转完成后(重连)

pre end start next
| | | |
... --> O ------> O --> ... --> O -> O ------> O --> ...
(前驱) (新头) (新尾) (后继)

Tips:缝合公式 :

1
2
pre.next.next = curr; // 1. 原来的头(现尾巴) -> 接住剩下的
pre.next = prev; // 2. 前驱节点 -> 接住新的头

🔹 场景 2: 整段反转,不用接回(两指针反转)

相关练习题

1. LeetCode 206. 反转链表

题意: 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

2. LeetCode 92. 反转链表 II

题意: 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 right 的链表节点,返回 反转后的链表 。

3. LeetCode 25. K 个一组翻转链表

题意: 给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。

k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。