-
p2 = p2.next;
:- 这一行代码的作用是将
p2
向前移动到它的下一个节点。 - 原本
p2
指向的是某个节点,这一行执行后,p2
指针将指向它的下一个节点,准备进行下一次比较和可能的连接。 - 这一步是为了在下一次循环时
p2
能够指向它的下一个节点,使得p2
和p1
继续比较和合并操作。
- 这一行代码的作用是将
ListNode mergeTwoLists(ListNode l1, ListNode l2) { // 虚拟头结点 ListNode dummy = new ListNode(-1), p = dummy; ListNode p1 = l1, p2 = l2; while (p1 != null && p2 != null) { // 比较 p1 和 p2 两个指针 // 将值较小的的节点接到 p 指针 if (p1.val > p2.val) { p.next = p2; p2 = p2.next; } else { p.next = p1; p1 = p1.next; } // p 指针不断前进 p = p.next; } if (p1 != null) { p.next = p1; } if (p2 != null) { p.next = p2; } return dummy.next; } 解释 p.next = p2; p2 = p2.next;
在这段代码中,关键部分是以下两行:
```java
p.next = p2;
p2 = p2.next;
```
### 解释
1. **`p.next = p2;`**:
- 这一行代码的作用是将指针 `p` 的 `next` 域指向 `p2` 当前所指向的节点。
- `p` 是当前合并链表的尾节点,通过 `p.next = p2`,将 `p2` 当前的节点接到合并链表的末尾。
- 换句话说,这一行代码将 `p2` 当前节点连接到新链表中。
2. **`p2 = p2.next;`**:
- 这一行代码的作用是将 `p2` 向前移动到它的下一个节点。
- 原本 `p2` 指向的是某个节点,这一行执行后,`p2` 指针将指向它的下一个节点,准备进行下一次比较和可能的连接。
- 这一步是为了在下一次循环时 `p2` 能够指向它的下一个节点,使得 `p2` 和 `p1` 继续比较和合并操作。
### 图示说明
假设当前链表的结构如下:
- `p1` 指向的链表: 1 -> 4 -> 6
- `p2` 指向的链表: 2 -> 3 -> 5
- `p` 是合并链表的当前末尾节点,初始时是 `dummy` 的位置
初始情况:
```
dummy -> -1 -> null
p -> -1 -> null
p1 -> 1 -> 4 -> 6
p2 -> 2 -> 3 -> 5
```
### 执行步骤
1. **第一次比较**:
- `p1.val (1)` 和 `p2.val (2)` 比较,`1 < 2`,所以将 `p1` 当前节点连接到 `p` 的 `next` 上,并移动 `p1`。
```java
p.next = p1;
p1 = p1.next;
p = p.next;
```
结果:
```
dummy -> -1 -> 1 -> null
p -> 1 -> null
p1 -> 4 -> 6
p2 -> 2 -> 3 -> 5
```
2. **第二次比较**:
- `p1.val (4)` 和 `p2.val (2)` 比较,`4 > 2`,所以将 `p2` 当前节点连接到 `p` 的 `next` 上,并移动 `p2`。
```java
p.next = p2;
p2 = p2.next;
p = p.next;
```
结果:
```
dummy -> -1 -> 1 -> 2 -> null
p -> 2 -> null
p1 -> 4 -> 6
p2 -> 3 -> 5
```
3. **第三次比较**:
- `p1.val (4)` 和 `p2.val (3)` 比较,`4 > 3`,所以将 `p2` 当前节点连接到 `p` 的 `next` 上,并移动 `p2`。
```java
p.next = p2;
p2 = p2.next;
p = p.next;
```
结果:
```
dummy -> -1 -> 1 -> 2 -> 3 -> null
p -> 3 -> null
p1 -> 4 -> 6
p2 -> 5
```
4. **第四次比较**:
- `p1.val (4)` 和 `p2.val (5)` 比较,`4 < 5`,所以将 `p1` 当前节点连接到 `p` 的 `next` 上,并移动 `p1`。
```java
p.next = p1;
p1 = p1.next;
p = p.next;
```
结果:
```
dummy -> -1 -> 1 -> 2 -> 3 -> 4 -> null
p -> 4 -> null
p1 -> 6
p2 -> 5
```
5. **第五次比较**:
- `p1.val (6)` 和 `p2.val (5)` 比较,`6 > 5`,所以将 `p2` 当前节点连接到 `p` 的 `next` 上,并移动 `p2`。
```java
p.next = p2;
p2 = p2.next;
p = p.next;
```
结果:
```
dummy -> -1 -> 1 -> 2 -> 3 -> 4 -> 5 -> null
p -> 5 -> null
p1 -> 6
p2 -> null
```
6. **剩余部分处理**:
- `p2` 已经为 `null`,将 `p1` 剩余的部分连接到 `p` 的 `next` 上。
```java
if (p1 != null) {
p.next = p1;
}
```
最终结果:
```
dummy -> -1 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6
```
返回 `dummy.next` 即得到合并后的有序链表:
```
1 -> 2 -> 3 -> 4 -> 5 -> 6
```
### 知识点总结
1. **链表操作**:
- 使用指针操作进行链表节点的连接和遍历。
- 使用 `dummy` 哨兵节点简化边界条件处理,避免处理 `null` 指针异常。
2. **条件判断和指针移动**:
- 通过条件判断决定连接 `p1` 还是 `p2` 当前节点到新的链表。
- 移动 `p1` 和 `p2` 指针使得它们指向下一个节点,继续比较和连接操作。
3. **合并过程**:
- 逐步将两个有序链表合并成一个新的有序链表,保持原有链表节点的顺序。
通过上述过程,我们完成了两个有序链表的合并,保持了链表的有序性,并且每个节点都被正确地连接到新的链表中。