目录
一、题目
二、C++解题程序框架
1. 结构体定义
2. 类定义
3. 输入输出说明
三、链表指针
1. 链表指针的基本概念
2. 链表指针的常见操作
1. 遍历链表
2. 插入节点
3. 删除节点
3. 链表指针操作的注意事项
4. 总结
四、解题
方法一:迭代法
方法二:递归法
一、题目
二、C++解题程序框架
/*** struct ListNode {* int val;* struct ListNode *next;* ListNode(int x) : val(x), next(nullptr) {}* };*/
#include <cstddef>
#include <cstdio>
class Solution {
public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param head ListNode类 * @return ListNode类*/ListNode* ReverseList(ListNode* head) {// write code here}
};
这段代码是一个C++程序的框架,以下是对代码的详细解释:
1. 结构体定义
struct ListNode {int val;struct ListNode *next;ListNode(int x) : val(x), next(nullptr) {}
};
-
ListNode
是一个结构体,用于表示链表中的节点。 -
每个节点包含两个成员:
-
int val
:存储节点的值。 -
struct ListNode *next
:指向下一个节点的指针。
-
-
构造函数
ListNode(int x)
用于初始化节点的值为x
,并将next
指针初始化为nullptr
。
2. 类定义
class Solution {
public:ListNode* ReverseList(ListNode* head) {// write code here}
};
-
Solution
是一个类,包含一个公共方法ReverseList
。 -
方法
ReverseList
的作用是反转链表。-
参数
ListNode* head
:表示链表的头节点。 -
返回值
ListNode*
:返回反转后的链表的头节点。
-
3. 输入输出说明
-
输入:链表的头节点
head
。-
例如,链表
1 -> 2 -> 3 -> nullptr
的头节点是head
。
-
-
输出:反转后的链表的头节点。
-
对于上述输入,输出应为链表
3 -> 2 -> 1 -> nullptr
的头节点。
-
三、链表指针
在链表操作中,指针是一个非常重要的概念。链表是由一系列节点组成的,每个节点包含两部分:数据(val
和)指向下一个节点的指针(next
)。通过指针的操作,我们可以实现链表的遍历、插入、删除等操作。
1. 链表指针的基本概念
在链表中,指针用于连接各个节点。例如,对于一个简单的单链表,每个节点的 next
指针指向下一个节点,最后一个节点的 next
指针通常为 nullptr
,表示链表的结束。
2. 链表指针的常见操作
1. 遍历链表
遍历链表是链表操作中最基本的操作之一。通过指针逐个访问链表中的每个节点。
void PrintList(ListNode* head) {ListNode* current = head; // 使用一个指针指向当前节点while (current != nullptr) { // 当指针不为空时继续遍历printf("%d -> ", current->val); // 打印当前节点的值current = current->next; // 移动指针到下一个节点}printf("nullptr\n"); // 表示链表结束
}
2. 插入节点
在链表中插入节点通常需要修改指针的指向。例如,插入一个新节点到链表的头部、尾部或中间。
-
插入到头部:
void InsertAtHead(ListNode*& head, int value) {ListNode* newNode = new ListNode(value); // 创建一个新节点newNode->next = head; // 新节点的 next 指向原头节点head = newNode; // 更新头指针
}
-
插入到尾部:
void InsertAtTail(ListNode*& head, int value) {ListNode* newNode = new ListNode(value); // 创建一个新节点if (head == nullptr) { // 如果链表为空,直接将新节点作为头节点head = newNode;} else {ListNode* current = head; // 使用一个指针指向当前节点while (current->next != nullptr) { // 找到链表的最后一个节点current = current->next;}current->next = newNode; // 将新节点插入到尾部}
}
3. 删除节点
删除链表中的节点也需要操作指针。例如,删除链表中的特定某个值的节点。
void DeleteNode(ListNode*& head, int value) {if (head == nullptr) return; // 如果链表为空,直接返回// 如果头节点就是要删除的节点if (head->val == value) {ListNode* temp = head; // 保存头节点head = head->next; // 更新头指针delete temp; // 释放原头节点的内存return;}// 遍历链表,找到要删除的节点的前一个节点ListNode* current = head;while (current->next != nullptr && current->next->val != value) {current = current->next;}// 如果找到了要删除的节点if (current->next != nullptr) {ListNode* temp = current->next; // 保存要删除的节点current->next = current->next->next; // 修改指针,跳过要删除的节点delete temp; // 释放内存}
}
3. 链表指针操作的注意事项
-
指针的初始化:在操作链表时,指针需要正确初始化,避免野指针。
-
指针的更新:在修改指针时,要确保不会丢失对链表的引用,避免内存泄漏。
-
边界条件:处理链表为空或只有一个节点的情况,避免程序出错。
-
内存管理:在删除节点时,记得释放节点占用的内存,避免内存泄漏。
4. 总结
链表操作的核心是通过指针来连接和操作节点。指针的正确使用是实现链表各种操作的基础。通过熟练掌握指针的操作,可以高效地实现链表的遍历、插入、删除和反转等功能。
四、解题
方法一:迭代法
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; // 最终 prev 指向新的头节点
}
方法二:递归法
ListNode* ReverseList(ListNode* head) {if (head == nullptr || head->next == nullptr) {return head; // 如果链表为空或只有一个节点,直接返回}ListNode* newHead = ReverseList(head->next); // 递归反转后续链表head->next->next = head; // 将当前节点的下一个节点的 next 指向当前节点head->next = nullptr; // 当前节点的 next 指向 nullptrreturn newHead; // 返回新的头节点
}