1. 链表反转的核心原理与实现价值
链表反转是数据结构与算法中最经典的入门问题之一,也是技术面试中出现频率最高的考题。我第一次在真实项目中遇到这个问题,是在处理一个需要逆向遍历用户操作记录的需求时。当时系统采用单向链表存储用户行为序列,但产品要求按时间倒序展示,这就必须对链表进行原地反转。
链表反转之所以重要,是因为它考察了开发者对指针操作和链表结构的理解深度。与数组不同,链表节点在内存中不是连续存储的,每个节点只保存下一个节点的地址。反转操作需要在不使用额外空间的情况下,通过改变节点间的指针指向来实现顺序翻转。这就像要把一列火车的所有车厢调头,但只能通过改变车厢之间的连接杆来完成。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 链表节点结构与基础定义
2.1 链表节点的标准定义
在C++中,链表节点通常定义为结构体:
cpp复制struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr) {}
};
这个简单的结构包含两个成员:val存储节点值,next是指向下一个节点的指针。构造函数初始化节点值并将指针设为nullptr(C++11中的空指针常量),避免野指针问题。
注意:在实际工程中,建议使用智能指针(如std::unique_ptr)管理节点内存,但在算法题和面试中通常简化为裸指针以聚焦核心逻辑。
2.2 链表的内存布局特性
链表与数组最根本的区别在于内存分布:
- 数组:连续内存块,支持随机访问(O(1)时间复杂度)
- 链表:非连续内存,通过指针链接,只能顺序访问(O(n)时间复杂度)
这种差异决定了反转算法的设计思路。数组反转可以通过首尾交换元素实现,而链表反转必须通过指针操作来完成。
3. 迭代法反转链表的完整实现
3.1 三指针法标准实现
迭代法是反转链表最直观的解法,时间复杂度O(n),空间复杂度O(1)。以下是完整实现:
cpp复制ListNode* reverseList(ListNode* head) {
ListNode *prev = nullptr;
ListNode *curr = head;
while (curr != nullptr) {
ListNode *nextTemp = curr->next; // 保存下一个节点
curr->next = prev; // 反转指针
prev = curr; // 前移prev
curr = nextTemp; // 前移curr
}
return prev; // 新链表头
}
3.2 关键步骤拆解
-
初始化阶段:
prev初始化为nullptr,表示反转后链表的末尾curr初始化为head,指向当前待处理节点
-
循环体四步操作:
- 保存curr的下一个节点(防止断链)
- 将curr的next指针指向prev(反转操作核心)
- prev移动到curr位置(为下一轮做准备)
- curr移动到之前保存的next位置
-
终止条件:
- 当curr为nullptr时,表示已处理完所有节点
- 此时prev指向
