// 反转以 a 为头结点的链表
public ListNode reverse(ListNode a) {
ListNode pre = null;
ListNode cur = a;
ListNode nxt = a;
while (cur != null) {
nxt = cur.next; // 保存当前节点的下一个节点
cur.next = pre; // 反转当前节点的指针
pre = cur; // pre 移动到当前节点
cur = nxt; // cur 移动到下一个节点
}
// 返回反转后的头结点
return pre;
}到底是需要哪种思考模型才能想到这一步 pre = cur; // pre 移动到当前节点
cur = nxt; // cur 移动到下一个节点
要理解并想出这段反转链表代码的最后两步:`pre = cur; // pre 移动到当前节点` 和 `cur = nxt; // cur 移动到下一个节点`,需要一种称为 **迭代更新模型** 的思考方式。这种思考方式的核心是通过迭代逐步更新指针位置,以便在遍历链表的同时 完成反转操作。以下是详细的解释:
### 迭代更新模型
1. **初始状态设定**:
- `pre`:初始值为 `null`,表示反转后链表的新头节点的前一个节点(起始时为空)。
- `cur`:初始值为 `a`,表示当前正在处理的节点,从链表头开始。
- `nxt`:初始值也为 `a`,用来保存当前节点的下一个节点,以防止在操作中丢失对链表剩余部分的引用。
2. **核心迭代逻辑**:
- 每次迭代时,先保存 `cur` 的下一个节点 `nxt`,然后反转 `cur` 的指针,使其指向 `pre`。接着,更新 `pre` 和 `cur` 指针,准备处理下一个节点。
### 详细步骤解释
1. **保存当前节点的下一个节点**:`nxt = cur.next;`
- 这一步是为了确保在改变 `cur.next` 之前,先保存 `cur` 的下一个节点 `nxt`,防止丢失链表的后续部分。
2. **反转当前节点的指针**:`cur.next = pre;`
- 将当前节点 `cur` 的 `next` 指针指向前一个节点 `pre`,实现当前节点的指针反转。这一步骤完成了链表部分的反转。
3. **更新指针位置**:
- `pre = cur;`:将 `pre` 移动到当前节点位置,为下一次迭代做好准备。这一步是关键,因为在下一次迭代中,当前节点 `cur` 会变成前一个节点 `pre`,用于反转下一个节点的指针。
- `cur = nxt;`:将 `cur` 移动到下一个节点位置,即 `nxt`,继续处理链表的剩余部分。
### 为什么需要这种思考模型
- **分步迭代更新**:通过迭代逐步更新 `pre` 和 `cur` 指针,可以在遍历链表的同时,逐步反转每个节点的指针。这个过程是线性的,不会遗漏任何节点。
- **指针依赖关系**:在反转链表时,每个节点的 `next` 指针都依赖于前一个节点的指针位置。因此,必须先更新 `pre` 指针,再更新 `cur` 指针,才能确保每次迭代都能正确反转节点的指针。
- **防止链表断裂**:通过保存 `nxt`,可以防止在指针反转过程中丢失对链表剩余部分的引用,从而保证链表的完整性。
### 示例代码重述
通过代码注释详细解释:
```java
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
}
public class ReverseList {
// 反转以 a 为头结点的链表
public ListNode reverse(ListNode a) {
ListNode pre = null; // 初始化 pre 为 null
ListNode cur = a; // 初始化 cur 为链表头节点 a
ListNode nxt = a; // 初始化 nxt 为链表头节点 a
while (cur != null) { // 遍历链表直到 cur 为 null
nxt = cur.next; // 保存当前节点的下一个节点
cur.next = pre; // 反转当前节点的指针
pre = cur; // pre 移动到当前节点
cur = nxt; // cur 移动到下一个节点
}
// 返回反转后的头结点
return pre;
}
public static void main(String[] args) {
ReverseList rl = new ReverseList();
ListNode head = new ListNode(1);
head.next = new ListNode(2);
head.next.next = new ListNode(3);
head.next.next.next = new ListNode(4);
head.next.next.next.next = new ListNode(5);
ListNode result = rl.reverse(head);
// 输出反转后的链表
while (result != null) {
System.out.print(result.val + " ");
result = result.next;
}
}
}
```
### 总结
通过理解迭代更新模型,可以清晰地看到反转链表的每一步操作是如何通过更新指针位置来逐步实现链表的反转。这个思考模型不仅有助于理解链表的反转操作,还可以应用于其他需要逐步更新指针的链表操作问题。