难度参考
难度:简单
分类:链表
难度与分类由我所参与的培训课程提供,但需要注意的是,难度与分类仅供参考。以下内容均为个人笔记,旨在督促自己认真学习。
题目
反转一个单链表(不带头节点)
示例1:
输入:1->2->3->4->5->null
输出:5->4->3->2->1->null
解释:链表反转后顺序逆序,由1->2->3->4->5->null,变成了5->4->3->2->1->null
思路
初始化两个指针:prev
和 current
,分别指向当前节点的前一个节点和当前节点。
- 使用一个临时指针
nextNode
保存当前节点的下一个节点,以备后续使用。 - 在循环中,将当前节点的
next
指针指向prev
,实现反转操作。 - 移动
prev
和current
指针,继续向后遍历链表。 - 重复步骤 3 和 4,直到
current
指针指向链表末尾,即current
为NULL
。 - 返回反转后的链表的头节点,即原链表的末尾节点
示例
理解链表反转可能有些抽象,但可以通过将其拆分成简单的步骤来理解。以下是更具体的步骤和示例,帮助你更好地理解链表反转:
假设我们有一个链表:1 -> 2 -> 3 -> 4 -> 5 -> null
- 初始化两个指针,
prev
和current
,初始时都指向null
。 - 从链表的头部开始遍历,首先处理节点
1
:prev
指向null
current
指向1
- 在每一步中,我们将
current
的next
指向prev
,即将1 -> null
变成1 <- null
,然后移动指针:prev
指向1
current
指向2
- 重复上述步骤,将每个节点的
next
指向前一个节点,直到到达链表末尾:prev
指向4
current
指向5
- 最终,链表变成:5 -> 4 -> 3 -> 2 -> 1 -> null
通过不断将当前节点的 next
指向前一个节点,我们逐步完成了链表的反转。这是链表反转的基本思路。希望这个示例有助于你更好地理解这个过程。
梳理
-
首先,我们定义了一个单链表节点结构
ListNode
,其中包括一个整数值val
用于存储节点的值,以及一个指向下一个节点的指针next
。 -
然后,定义了一个
reverseList
函数,它接受一个头节点head
作为参数,用于反转单链表。 -
在
reverseList
函数中,我们初始化了两个指针prev
和current
,开始时都指向NULL
。prev
用于存储当前节点的前一个节点,而current
用于表示当前节点。 -
使用
while
循环遍历链表,循环条件是current != NULL
,即遍历链表直到当前节点为空(链表末尾)。 -
在每次循环中,我们首先保存下一个节点的指针为
nextNode
,以备后续使用。 -
然后,将当前节点的
next
指针指向前一个节点prev
,这样就完成了当前节点指向前一个节点的反转操作。 -
接着,将
prev
指针移动到当前节点,为下一轮循环做准备。 -
最后,将
current
指针移动到下一个节点nextNode
,继续下一轮循环。 -
当循环结束时,
prev
指针指向原链表的末尾节点,即反转后的链表的头节点,因此我们返回prev
作为反转后链表的新头节点。 -
在
main
函数中,我们创建了一个示例链表,然后调用printList
函数打印原始链表,再调用reverseList
函数进行链表反转,最后再次调用printList
函数打印反转后的链表。
代码
#include <iostream>
using namespace std;
// 定义单链表节点结构
struct ListNode {
int val; // 存储节点的值
ListNode* next; // 指向下一个节点的指针
ListNode(int x) : val(x), next(NULL) {} // 构造函数,初始化节点的值和指针
};
// 反转单链表的函数
ListNode* reverseList(ListNode* head) {
ListNode* prev = NULL; // 初始化前一个节点为NULL,用于存储当前节点的前一个节点
ListNode* current = head; // 初始化当前节点为头节点,从头节点开始反转
while (current != NULL) { // 循环遍历链表,直到当前节点为NULL(即链表末尾)
ListNode* nextNode = current->next; // 保存下一个节点的指针,以备后续使用
current->next = prev; // 反转当前节点的指针方向,使其指向前一个节点
prev = current; // 移动prev指针,指向当前节点,为下一轮循环做准备
current = nextNode; // 移动current指针,指向下一个节点,继续反转操作
}
return prev; // 返回新的头节点,即原链表的末尾节点
}
// 打印链表的函数
void printList(ListNode* head) {
ListNode* current = head; // 从头节点开始遍历链表
while (current != NULL) { // 循环遍历链表,直到当前节点为NULL
cout << current->val << " "; // 打印当前节点的值
current = current->next; // 移动到下一个节点
}
cout << "null" << endl; // 打印链表末尾的null表示链表结束
}
int main() {
// 创建示例链表:1->2->3->4->5->null
ListNode* head = new ListNode(1); // 创建头节点并初始化值为1
head->next = new ListNode(2); // 创建下一个节点并初始化值为2
head->next->next = new ListNode(3); // 创建下一个节点并初始化值为3
head->next->next->next = new ListNode(4); // 创建下一个节点并初始化值为4
head->next->next->next->next = new ListNode(5); // 创建下一个节点并初始化值为5
cout << "原始链表:" << endl;
printList(head); // 打印原始链表
// 反转链表
ListNode* reversedHead = reverseList(head); // 调用反转函数
cout << "反转后的链表:" << endl;
printList(reversedHead); // 打印反转后的链表
return 0;
}
时间复杂度:O(n)
空间复杂度:O(1)