反转链表题目要求
反转一个单链表。
示例:
输入: 1->2->3->4->5->NULL
输出: 5->4->3->2->1->NULL
非递归方法
思路
反转链表直白讲就是让每个结点的next引用指向该结点的上一个结点(头结点则是next变为null)。
第一步,定义引用cur代表当前结点,pre代表上一个结点。cur初始指向头结点,pre初始为null。这里用一个有3个结点的链表来叙述整个过程,如下图1。
第二步:循环。
第一次循环
(1)用临时引用temp指向cur结点的下一个结点,防止cur的next改变指向后访问不到下一个结点。如下图2.1。
(2)cur的next指向前一结点(这里把null也看做结点),就是将pre值赋给next值。如下图2.2。
(3)pre和cur都向右移一个结点,具体实现方法即为pre指向cur结点,cur指向temp结点。如下图2.3。
第二次循环
(1)temp指向cur结点的下一个结点。如下图2.4。
(2)cur的next指向前一结点。如下图2.5。
(3)pre和cur都向右移一个结点。如下图2.6。
第三次循环
(1)temp指向cur结点的下一个结点(这里把null也看做结点)。如下图2.7。
(2)cur的next指向前一结点。如下图2.8。
(3)pre和cur都向右移一个结点。如下图2.9。
到此循环结束,此时cur值为null,可把循环的结束条件定为cur==null。
代码如下,用Java实现。
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
public class ReverseLinkedList1 {
public ListNode reverseList(ListNode head) {
//第一步,定义引用pre指向null,cur指向头结点,cur代表当前结点,pre代表当前结点的上一个结点
ListNode pre = null;
ListNode cur = head;
//第二步,循环。先定义一个临时引用temp指向cur的下一个结点
ListNode temp = null;
while (cur != null) {
//(1)temp指向cur的下一个结点
temp = cur.next;
//(2)cur的next指向cur的上一个结点
cur.next = pre;
//(3)pre和cur右移,pre指向cur结点,cur指向temp结点
pre = cur;
cur = temp;
}
//循环结束后,cur和temp都指向null,pre指向原来链表的最后一个结点,此时为已经反转的链表的头结点
//第三步,head指向最后一个结点
head = pre;
return head;
}
public static void main(String[] args) {
ReverseLinkedList1 reverseLinkedList1 = new ReverseLinkedList1();
//新建链表并依次插入1,2,3,4,5
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 newHead = reverseLinkedList1.reverseList(head);
ListNode p = newHead;
while (p != null) {
System.out.print(p.val + " ");
p = p.next;
}
System.out.println();
}
}
运行结果如下:
递归方法
递归方法本人并没有想到,这里给出对LeetCode官方给出的递归方法的理解。先上代码。
public class ReverseLinkedList2 {
public ListNode reverseList(ListNode p) {
if(p == null || p.next == null) {
return p;
}
ListNode tail = this.reverseList(p.next);
p.next.next = p;
p.next = null;
return tail;
}
public static void main(String[] args) {
//新建链表并依次插入1,2,3,4,5
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);
ReverseLinkedList2 reverseLinkedList2 = new ReverseLinkedList2();
//调用头结点的reverseList方法,返回值为原来链表的尾结点,也就是现在新链表的头结点
ListNode newHead = reverseLinkedList2.reverseList(head);
//遍历新链表
ListNode p = newHead;
while (p != null) {
System.out.print(p.val + " ");
p = p.next;
}
System.out.println();
}
}
main方法中调用头结点的reverseList方法,这个方法内部的执行过程是:
(1)判断当前结点是否为尾结点,如果是尾结点则返回尾结点;否则继续下一步。
(2)调用下一结点的reverseList方法。
(3)反转当前结点。
除了尾结点,其他结点只有执行过程的后两步。
所以头结点先调用第2结点的reverseList方法,而第2结点的reverseList方法又会调用第3结点的reverseList方法,这样就递归到尾结点,尾结点只有执行过程的第一步:返回尾结点。
然后从后往前逐步完成每个结点的reverseList方法:(此时当前结点之后的结点都已完成反转)只有反转自己这一步。最后完成头结点的反转,整个链表就反转完成了。
运行结果如下: