1. 引言
单链表(Singly Linked List)是一种常见的数据结构,在算法和数据结构的学习中占有重要地位。翻转单链表是一道经典的面试题,本文将介绍几种常见的 Java 实现方法,并详细讲解关键步骤的含义。
2. 单链表定义
我们可以先定义一个链表节点类:
java
class ListNode {
int val;
ListNode next;
ListNode(int val) {
this.val = val;
this.next = null;
}
}
3. 迭代法实现链表翻转(附详细注释)
迭代法是最常用的方法之一,使用三个指针完成整个翻转过程:
java
public class ReverseLinkedList {
public static ListNode reverseList(ListNode head) {
ListNode prev = null; // 初始时,前一个节点指针为 null
ListNode current = head; // 当前处理的节点从链表头开始
while (current != null) {
ListNode nextNode = current.next; // 1. 暂存当前节点的下一个节点
current.next = prev; // 2. 将当前节点的指针指向前一个节点
/*
* 原本 current 节点是指向下一个节点的,
* 比如 current 是 2,它的 next 是 3,
* 这一步将它反过来指向前面的 prev,
* 也就是把 2 -> 3 改成 2 -> 1(假设 prev 是 1),
* 从而实现链条的反向连接。
*/
prev = current; // 3. 移动 prev 指针
/*
* 这一步是让 prev 继续前进,指向当前处理好的节点,
* 为下一轮翻转做准备。
* 假设刚刚处理的是 2,现在 prev 变成 2,
* 这样下一轮就可以把 3 的指针指向 2 了。
*/
current = nextNode; // 4. 继续处理下一个节点
}
return prev; // 最终 prev 会指向新的头节点
}
public static void main(String[] args) {
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 reversedHead = reverseList(head);
while (reversedHead != null) {
System.out.print(reversedHead.val + " -> ");
reversedHead = reversedHead.next;
}
System.out.println("NULL");
}
}
复杂度分析
- 时间复杂度:
O(n)
,需要遍历每个节点一次; - 空间复杂度:
O(1)
,只用了常数个变量。
4. 递归法实现链表翻转
递归法思路清晰,适合理解递归调用,但需要额外的调用栈空间:
java
public class ReverseLinkedListRecursive {
public static ListNode reverseList(ListNode head) {
if (head == null || head.next == null) {
return head; // 递归出口,返回最后一个节点作为新头
}
ListNode newHead = reverseList(head.next); // 递归反转后续节点
head.next.next = head; // 让后一个节点指向当前节点,实现反转
head.next = null; // 切断当前节点与后续的连接,避免成环
return newHead; // 返回新头节点
}
public static void main(String[] args) {
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 reversedHead = reverseList(head);
while (reversedHead != null) {
System.out.print(reversedHead.val + " -> ");
reversedHead = reversedHead.next;
}
System.out.println("NULL");
}
}
复杂度分析
- 时间复杂度:
O(n)
,每个节点访问一次; - 空间复杂度:
O(n)
,递归调用栈占用了额外空间。
5. 总结
- 迭代法:空间效率高,适用于大多数场景;
- 递归法:代码简洁,适合展示递归思维,但不适合超长链表。
建议优先使用迭代法,避免递归造成的栈溢出问题。理解链表翻转的本质,就是反转每个节点的 next
指针方向,直到整个链表翻转完成。
希望本文对你理解和实现单链表翻转有所帮助!