c++学习日记——反转链表

反转链表的两种实现方法(迭代 & 递归)

反转链表(Reverse Linked List)是链表中最经典、最基础、最常考的算法题之一。它不仅考察你对指针的理解,还能帮助你打好链表操作的基本功。

本文将使用 C++ 实现两种主流方法:

  • ✅ 迭代法(推荐)
  • ✅ 递归法(简洁但不一定高效)

🧩 题目描述

给定一个单链表头指针 head,将其原地反转,并返回新的头指针。

例子:

输入:1 -> 2 -> 3 -> 4 -> 5 -> NULL
输出:5 -> 4 -> 3 -> 2 -> 1 -> NULL


🏗️ 链表结构定义

struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

方法一:迭代法(双指针)

这是最常用的方式,使用 prevcurr 两个指针逐个反转链表中的 next 指针。

🌱 思路解析

初始状态:

prev = NULL
curr = head

每次迭代步骤:

  1. 保存下一个节点:next = curr->next
  2. 反转当前指针:curr->next = prev
  3. 指针前移:prev = currcurr = next

直到 curr == NULL,说明处理完毕,prev 就是新的头节点。

✅ 代码实现

ListNode* reverseList(ListNode* head) {
    ListNode* prev = nullptr;
    ListNode* curr = head;

    while (curr) {
        ListNode* next = curr->next;  // 保存下一个节点
        curr->next = prev;            // 反转指针
        prev = curr;                  // 移动 prev 和 curr
        curr = next;
    }

    return prev;
}

📊 时间 & 空间复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)(原地反转)

方法二:递归法(从尾到头反转)

递归地反转子链表,然后把当前节点挂在子链表后面。

🌱 思路解析

设:

head = 1
head->next = 2 -> 3 -> NULL

递归地反转 head->next 部分,然后让 head->next->next = head,再让 head->next = NULL

✅ 代码实现

ListNode* reverseList(ListNode* head) {
    if (head == nullptr || head->next == nullptr) return head;

    ListNode* newHead = reverseList(head->next);  // 反转子链表
    head->next->next = head;  // 当前节点接到子链表尾部
    head->next = nullptr;

    return newHead;
}

📊 时间 & 空间复杂度

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)(递归栈)

🔍 对比总结

方法 时间复杂度 空间复杂度 特点
迭代法 O(n) O(1) 原地反转,推荐使用
递归法 O(n) O(n) 简洁清晰,但有栈开销

📌 补充:图示理解迭代法

初始链表:

[1] -> [2] -> [3] -> [4] -> NULL

每一步的操作:

  • 第一次循环:

    • curr = 1, next = 2
    • 1->next = NULL
    • prev = 1, curr = 2
  • 第二次循环:

    • curr = 2, next = 3
    • 2->next = 1
    • prev = 2, curr = 3
  • 第三次循环:

    • curr = 3, next = 4
    • 3->next = 2
    • prev = 3, curr = 4
  • 第四次循环:

    • curr = 4, next = NULL
    • 4->next = 3
    • prev = 4, curr = NULL

最终链表变为:

[4] -> [3] -> [2] -> [1] -> NULL

🧠 提示:写链表题的常用套路

  • prev, curr, next 三指针配合使用
  • 考虑空链表和只有一个节点的情况
  • 写递归时明确“返回什么?做什么?连接什么?

🧪 测试用例建议

ListNode* head = new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);

ListNode* newHead = reverseList(head);

// 输出链表进行验证
while (newHead) {
    std::cout << newHead->val << " ";
    newHead = newHead->next;
}
// 期望输出:3 2 1

✅ 总结

反转链表是链表操作的“Hello World”。掌握迭代法的指针操作、理解递归的调用栈行为,对于后续处理复杂链表题(如:判断回文、k 个一组反转、链表排序等)都有极大帮助。


posted @ 2025-07-25 14:45  seekwhale13  阅读(155)  评论(0)    收藏  举报