链表大家都不陌生了,而且它也是面试中易考的数据结构,掌握链表的使用非常重要。
首先,定义一个链表:
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
单链表的反转分为迭代和递归两张方式,首先来介绍迭代的方式:
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null){
ListNode next = curr.next; //1
curr.next = prev; //2
prev = curr; //3
curr = next; //4
}
return prev;
}
对标号的代码进行解读:
-
第一行代码: ListNode next = curr.next;
将curr.next赋值给next变量,也就是说next指向了节点2,先将节点2保存起来。 -
第二行代码: curr.next = prev;
将prev变量赋值给了head.next,即节点1指向了null。 -
第三行代码: prev = curr;
将curr赋值给了prev,即prev指向节点1,将节点1设为“上一个节点”。 -
第四行代码:curr = next;
将next赋值给curr,即curr指向了节点2。将节点2设置为“头结点”。
一次循环的具体过程就是这样。
所以总结一下单链表的反转:
- 保存当前头结点的下个节点。
- 将当前头结点的下一个节点指向“上一个节点”,这一步是实现了反转。
- 将当前头结点设置为“上一个节点”。
- 将保存的下一个节点设置为头结点。
递归实现
先反转后面的链表,从最后面的两个结点开始反转,依次向前,将后一个链表结点指向前一个结点,注意每次反转后要将原链表中前一个结点的指针域置空,表示将原链表中前一个结点指向后一个结点的指向关系断开。
public ListNode reverseList(ListNode head) {
//终止条件,找到最后一个节点
if (head == null || head.next == null) return head;
ListNode p = reverseList(head.next); //先反转后面的链表,从最后面的两个节点开始
head.next.next = head; //将后一个节点指向前一个节点
head.next = null; //将原链表中前一个节点指向后一个节点的关系断开
return p;
}