Java 实现单链表翻转(附详细注释)

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 指针方向,直到整个链表翻转完成。

希望本文对你理解和实现单链表翻转有所帮助!

相关推荐
yangzhi_emo3 分钟前
ES6笔记2
开发语言·前端·javascript
界面开发小八哥10 分钟前
「Java EE开发指南」如何用MyEclipse创建一个WEB项目?(三)
java·ide·java-ee·myeclipse
idolyXyz36 分钟前
[java: Cleaner]-一文述之
java
一碗谦谦粉1 小时前
Maven 依赖调解的两大原则
java·maven
emplace_back1 小时前
C# 集合表达式和展开运算符 (..) 详解
开发语言·windows·c#
jz_ddk1 小时前
[学习] C语言数学库函数背后的故事:`double erf(double x)`
c语言·开发语言·学习
萧曵 丶1 小时前
Rust 所有权系统:深入浅出指南
开发语言·后端·rust
netyeaxi1 小时前
Java:使用spring-boot + mybatis如何打印SQL日志?
java·spring·mybatis
xiaolang_8616_wjl1 小时前
c++文字游戏_闯关打怪2.0(开源)
开发语言·c++·开源