前言
反转链表是一道很经典的面试题,出现频率也较高,本文讲讲迭代法和递归法的解题思路
源码
迭代法
/**
* 传入一个单链表的头节点,将该链表反转
* 迭代法
*
* @param head
*/
public static ListNode iterative(ListNode head) {
// 定义当前节点为入参节点
ListNode cur = head;
// 定义两个前后指针,待用
// pre代表cur的上一节点,next代表cur的下一节点,在while中进行赋值
ListNode pre = null, next = null;
while (cur != null) {
// 将前指针定义为入参节点的下一节点
next = cur.next;
// 将当前节点的下一节点指向pre
cur.next = pre;
// 将pre指向当前节点
pre = cur;
// 将当前节点指向下一节点
cur = next;
}
// 在最后一轮的while循环中,pre指向了原本的链表尾
return pre;
}
要点
- 迭代法使用while循环来遍历链表
- cur表示当前遍历到的节点
- pre表示cur的上一个节点
- next表示cur的下一个节点
- pre和next在while循环体中进行赋值
- 其它要点见注释
递归法
/**
* 传入一个单链表的头节点,将该链表反转
* 递归法
*
* @param head
*/
public static ListNode recurse(ListNode head) {
// 设置限制条件
if (head == null || head.next == null) {
return head;
}
// 递操作获得链表尾节点
ListNode node = recurse(head.next);
// 获得链表尾节点之后,在链表尾的前一节点开始归操作
// 这一句的意思是,将当前head的下一节点的next指针指向当前head
head.next.next = head;
// 将当前head的next指针置空,在下次返回的时候再将其指向其前一节点(即上面那句的操作)
head.next = null;
// 返回尾节点node
return node;
}
要点
递归,根据字面我们都可以知道,是先递后归,在递归调用时先会发生递操作,触发限制条件时,再会发生归操作
递操作
- 限制条件为
head == null || head.next == null
,当遍历到尾节点时,返回尾节点(传入head为空时,返回空) - node递归获取的节点正是通过以上限制条件获取的尾节点
归操作
- 在递操作触发限制条件之后return,开始归操作,此时head指向倒数第二个节点
- 此时,
head.next
指向链表尾节点,head.next.next=head
将【链表尾结点】的next指针,指向【链表的倒数第二个节点head
】,用双向链表来解释的话就是node.next=node.pre
,这是链表反转的开始 - 以上是一轮归操作,在下一轮归操作中,head会指向【上一轮head】的前一节点,继续完成一轮归操作,直到指向原本的头节点
总结
以上就是反转链表的两种常见解法
惯例测试:
public static void main(String[] args) {
// 生成链表 1->2->3->4
dataInit();
// 输出链表反转(迭代法)
System.out.println(LinkedListReverse.iterative(head).toString());
/**
* output: 4->3->2->1
*/
// 生成链表 1->2->3->4
dataInit();
// 输出链表反转(递归法)
System.out.println(LinkedListReverse.recurse(head).toString());
/**
* output: 4->3->2->1
*/
}