广告

C++如何实现链表反转?完整代码与面试题解析(数据结构与链表操作)

实现思路与核心概念

链表反转的基本原理

在 C++ 中,链表反转的经典做法通常使用两指针,通过遍历链表并逐步调整指针来实现就地翻转。核心思想是让每个节点的 next 指针指向前驱节点,从而把链表的方向逐步反转。原地完成、不依赖额外的动态存储,是最常见的实现策略。

具体来说,首先设置两个指针:前驱指针 prev当前指针 curr,以及一个保存下一个节点的临时变量 next。在遍历过程中,逐步完成三步操作:保存 next将 curr->next 指向 prev更新 prev 与 curr。当遍历结束时,prev 指向新链表的头节点。

struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}
};
ListNode* reverseList(ListNode* head) {ListNode* prev = nullptr;ListNode* curr = head;while (curr) {ListNode* next = curr->next;   // 保存下一个节点curr->next = prev;             // 将当前节点指向前驱prev = curr;                       // 移动前驱指针curr = next;                       // 继续遍历}return prev; // 新头节点
}

时间复杂度为 O(n)空间复杂度为 O(1),适用于大多数实际场景。

完整代码示例与逐步讲解

逐步实现要点

为了在实际场景中能直接运行,我们给出一个完整程序示例,包含链表的创建、反转、以及输出结果的辅助函数。完整程序要素包括创建链表、反转操作、以及结果打印,以帮助理解各步骤的数据流。

在实现中,边界情况处理是关键,如空链表、单节点链表都应能正确返回。迭代实现相对简单、栈深度有限,但若使用递归则需要关注潜在的栈溢出风险。

#include <iostream>
#include <initializer_list>struct ListNode {int val;ListNode* next;ListNode(int x) : val(x), next(nullptr) {}
};// 迭代法:就地反转
ListNode* reverseList(ListNode* head) {ListNode* prev = nullptr;ListNode* curr = head;while (curr) {ListNode* next = curr->next;curr->next = prev;prev = curr;curr = next;}return prev;
}// 辅助:用初始化列表创建链表
ListNode* buildList(std::initializer_list<int> vals) {ListNode* head = nullptr;ListNode** p = &head;for (int v : vals) {*p = new ListNode(v);p = &((*p)->next);}return head;
}void printList(ListNode* head) {ListNode* p = head;while (p) {std::cout << p->val;if (p->next) std::cout << " -> ";p = p->next;}std::cout << std::endl;
}int main() {ListNode* head = buildList({1, 2, 3, 4, 5});head = reverseList(head);printList(head);return 0;
}

通过上述完整程序,读者可以直观地看到创建链表、反转链表、输出结果的完整流程,并在本地环境中编译运行以验证。

面试题解析:数据结构与链表操作

常见题型与解题要点

在面试中,反转链表相关题目是高频考点,常见题型包括:反转整条链表、反转部分链表(从 m 到 n)、两两交换链表节点、以及合并两个有序链表。解题时要关注指针操作的明确性与边界条件,同时理解时间复杂度与空间复杂度

以“反转部分链表”为例,通常会引入一个哑结点(dummy node)来简化边界处理,结合双指针或递归的思路,在O(n) 时间内完成,空间复杂度通常为 O(1)(除了递归栈)。

C++如何实现链表反转?完整代码与面试题解析(数据结构与链表操作)

// 递归实现的反转(练习用)
ListNode* reverseListRecursive(ListNode* head) {if (!head || !head->next) return head;ListNode* rest = reverseListRecursive(head->next);head->next->next = head;head->next = nullptr;return rest;
}

两种实现各有优缺点:迭代实现更安全、无栈溢出风险,代码可读性高递归实现代码简洁,但在链表很长时可能造成栈溢出,因此在实际面试中需要权衡使用场景。

此外,面试扩展还包括:反转前 n 个节点、反转给定区间的链表、以及与其他数据结构的结合使用,这些题目进一步考察对链表指针的控制能力和对边界条件的处理能力。

广告

后端开发标签