反转链表的方法

反转链表(Reversing a Linked List)是链表操作中一个比较常见且重要的问题。反转链表的原理和实现思路并不复杂,但理解其背后的思想有助于更好地掌握链表的操作以及指针操作的逻辑。

反转链表的思想主要是通过逐步反转链表节点的指针方向,使链表的头节点变为尾节点,尾节点变为头节点,实现整个链表的“翻转”。

反转链表的基本思路

反转链表的思路可以概括为以下几步:

  1. 初始化指针

    • 初始化三个指针:prev 指向前一个节点,current 指向当前节点,next 指向当前节点的下一个节点。

    • 初始时,prevnullcurrent 为链表的头节点。

  2. 遍历链表

    • 在遍历过程中,将 current 节点的 next 指针指向 prev,实现当前节点指针的反转。

    • 更新 prevcurrent 指针,继续处理下一个节点。

  3. 更新头节点

    • current 遍历完链表时,prev 就是新的头节点,将其返回作为反转后的链表。

图解示意

考虑一个链表:1 -> 2 -> 3 -> 4 -> 5

  1. 初始状态:

    prev = null
    current = 1
    next = 2
  2. 第一步反转:

    1 -> null
    prev = 1
    current = 2
    next = 3
  3. 第二步反转:

    2 -> 1 -> null
    prev = 2
    current = 3
    next = 4
  4. 持续反转直到链表末尾:

    3 -> 2 -> 1 -> null
    prev = 3
    current = 4
    next = 5
  5. 最终状态:

    5 -> 4 -> 3 -> 2 -> 1 -> null
    prev = 5 (新的头节点)

代码实现

以下是反转单链表的Java实现:

class ListNode {
    int val;
    ListNode next;
    ListNode(int val) {
        this.val = val;
    }
}
​
public class ReverseLinkedList {
    public static ListNode reverseList(ListNode head) {
        ListNode prev = null;
        ListNode current = head;
​
        while (current != null) {
            // 暂存下一节点
            ListNode next = current.next;
            
            // 反转当前节点的指针
            current.next = prev;
            
            // 向前移动指针
            prev = current;
            current = next;
        }
​
        // 新的头节点
        return prev;
    }
​
    public static void printList(ListNode head) {
        ListNode current = head;
        while (current != null) {
            System.out.print(current.val + " ");
            current = current.next;
        }
        System.out.println();
    }
​
    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);
​
        System.out.print("Original List: ");
        printList(head);
​
        // 反转链表
        ListNode reversedHead = reverseList(head);
​
        System.out.print("Reversed List: ");
        printList(reversedHead);
    }
}

代码解释

  1. ListNode类:定义了链表节点类 ListNode

    • val 表示节点的值。

    • next 表示指向下一个节点的指针。

  2. reverseList函数

    • 初始化 prevnullcurrenthead

    • 在循环中,对于每一个 current 节点:

      • 暂存 current.nextnext

      • current.next 指向 prev 完成当前节点的指针反转。

      • 更新 prevcurrent,移动到下一个节点。

    • 循环结束后,返回 prev 作为新的头节点。

  3. printList函数:用于打印链表,用于验证结果。

  4. main函数

    • 创建一个测试链表 1 -> 2 -> 3 -> 4 -> 5

    • 打印原始链表。

    • 调用 reverseList 反转链表。

    • 打印反转后的链表。

递归方式的反转链表

让我们更详细地解释一下递归方式如何反转链表。递归的思想是通过不断调用自身来解决问题,每次递归调用处理链表的一部分,逐步解决问题,直到达到终止条件。

递归反转链表的过程

假设我们有一个链表 1 -> 2 -> 3 -> 4 -> 5,我们希望将其反转为 5 -> 4 -> 3 -> 2 -> 1

递归方法可以分为以下几个步骤:

  1. 终止条件:当链表为空(head == null)或只有一个节点时(head.next == null),直接返回头节点。这是链表反转的基本情况。

  2. 递归处理剩余部分:对链表的其余部分进行递归调用,使其反转。例如,当前链表 1 -> 2 -> 3 -> 4 -> 5 中,递归处理 2 -> 3 -> 4 -> 5 部分。

  3. 调整节点指向:将当前节点的next节点(即反转后的链表的尾部)指向当前节点,并将当前节点的next设为null,断开指向。

代码实现

以下是反转链表的递归代码实现及详细注释:

class ListNode {
    int val;
    ListNode next;
    ListNode(int val) {
        this.val = val;
    }
}
​
public class ReverseLinkedListRecursive {
​
    // 递归反转链表
    public static ListNode reverseListRecursive(ListNode head) {
        // 终止条件:链表为空或只有一个节点时,直接返回头节点
        if (head == null || head.next == null) {
            return head;
        }
​
        // 递归处理剩余链表
        ListNode newHead = reverseListRecursive(head.next);
​
        // 当递归返回时,处理当前节点和其下一个节点的连接关系
        head.next.next = head;
        head.next = null;
​
        // 返回新的头节点
        return newHead;
    }
​
    // 打印链表
    public static void printList(ListNode head) {
        ListNode current = head;
        while (current != null) {
            System.out.print(current.val + " ");
            current = current.next;
        }
        System.out.println();
    }
​
    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);
​
        System.out.print("Original List: ");
        printList(head);
​
        // 反转链表
        ListNode reversedHead = reverseListRecursive(head);
​
        System.out.print("Reversed List: ");
        printList(reversedHead);
    }
}

代码详解

  1. 基础节点结构

    class ListNode {
        int val;
        ListNode next;
        ListNode(int val) {
            this.val = val;
        }
    }

    ListNode类定义了链表节点。

  2. 递归反转链表的主函数

    public static ListNode reverseListRecursive(ListNode head) {
        if (head == null || head.next == null) {
            return head;
        }
    ​
        ListNode newHead = reverseListRecursive(head.next);
    ​
        head.next.next = head;
        head.next = null;
    ​
        return newHead;
    }
    • 终止条件

      if (head == null || head.next == null) {
          return head;
      }

      如果链表为空或只有一个节点,将直接返回头节点,这是递归终止条件。

    • 递归调用

      ListNode newHead = reverseListRecursive(head.next);

      处理当前节点的后续节点的反转。

    • 调整节点链接

      head.next.next = head;
      head.next = null;

      将当前节点的下一个节点的next指向当前节点,将当前节点的next设为null,以断开当前节点原来的指向,防止形成环。

    • 返回新头节点

      return newHead;

      最后返回新头节点,即反转后的最末节点。

例子解析

  1. 第一次进入递归

    • 链表:1 -> 2 -> 3 -> 4 -> 5

    • 处理2 -> 3 -> 4 -> 5

  2. 第二次进入递归

    • 链表:2 -> 3 -> 4 -> 5

    • 处理3 -> 4 -> 5

  3. 第三次进入递归

    • 链表:3 -> 4 -> 5

    • 处理4 -> 5

  4. 第四次进入递归

    • 链表:4 -> 5

    • 处理5

  5. 终止条件

    • 链表:5

    • 返回5作为新头节点

  6. 开始回溯和链接调整

    • 处理第四层返回:4.next.next = 4,即 5 -> 4,然后 4.next = null

    • 处理第三层返回:3.next.next = 3,即 4 -> 3,然后 3.next = null

    • 处理第二层返回:2.next.next = 2,即 3 -> 2,然后 2.next = null

    • 处理第一层返回:1.next.next = 1,即 2 -> 1,然后 1.next = null

最终返回新的头节点5,得到反转后的链表:5 -> 4 -> 3 -> 2 -> 1

希望这个详细解释能帮助你理解递归反转链表的过程和实现!如果还有任何问题,请随时提问。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值