在上节中练习了创建一个n个节点的,并从1开始依次递增的单链表,本节开始在上节代码的基础上进行单链表反转的练习。
单链表的反转主要通过递归来完成。话不多说直接上代码:
#include<iostream>
using namespace std;
//创建节点
class Listnode {
public:
int data;
Listnode* next;
Listnode(int x) :data(x), next(nullptr) {}
};
//创建链表
Listnode* createList(int n) {
//定义一个头节点
Listnode* head = nullptr;
//prev用来记录前一个节点
Listnode* prev = nullptr;
for (int i = 1; i <= n; i++) {
//创建新的节点 new
Listnode* newnode = new Listnode(i);
if (head == nullptr) {
head = newnode;
}
else {
//表示将新节点连接到链表中,即将新节点自己的地址放入前一个节点的next中(或者将前一个节点的地址指向新节点)
prev->next = newnode;
}
//直接将新节点赋值给prev,用于更新前一个节点,prev里就是新节点的data和next
prev = newnode;
}
return head;//返回头节点
}
//定义解决方案(反转链表)
class Solution {
public:
//构建反转函数
Listnode* ReverseList(Listnode* pHead) {
//若链表为空或到最后一个节点,递归终止
if (pHead == nullptr || pHead->next == nullptr) {
return pHead;
}
//递归到最后一个节点,从最后一个节点开始从后往前翻转
Listnode* ans = ReverseList(pHead->next);
//把后一个节点的地址指向前一个节点,前一个节点的地址赋空
pHead->next->next = pHead;
pHead->next = nullptr;
//返回头指针
return ans;
}
};
//打印链表
void printList(Listnode* head) {
while (head != nullptr) {
cout << head->data << " ";
head = head->next;
}
cout << endl;
}
//释放空间
void deleteList(Listnode* head) {
while (head != nullptr) {
Listnode* temp = head;
head = head->next;
delete temp;
}
}
int main(){
int n = 0;
cin >> n;
//创建链表
Listnode* head = createList(n);
//打印链表
cout << "原链表为:";
printList(head);
//反转链表
Solution solution;
Listnode* reversedHead = solution.ReverseList(head);
cout << "反转链表为:";
printList(reversedHead);
//释放内存
deleteList(head);
return 0;
}
笔记:
1.pHead->next->next = pHead;
这行代码的作用是让当前节点 pHead
的下一个节点的 next
指针指向当前节点 pHead
,从而反转链表中两个节点的指向关系。具体来说,它完成了对链表中一对相邻节点之间指针的反转操作。如果还不理解那就举个例子
假设我们有一个链表如下所示:
A -> B -> C -> D -> nullptr
当递归到节点 B
时,当前节点 pHead
是 B
,pHead->next
是 C
,pHead->next->next
是 D
。我们希望将节点 C
的 next
指针指向 B
,从而反转这两个节点之间的指向关系。
通过执行 pHead->next->next = pHead;
,我们改变了链表的结构,使得 C
的 next
指针指向 B
:
A -> B <- C -> D -> nullptr
为了更好地理解这行代码,我们来看一下递归的上下文。在 ReverseList
函数中,递归逐步反转每个节点与其后继节点之间的关系。以下是一个详细的分步解释:
-
递归反转后续节点:
ListNode* ans = ReverseList(pHead->next);
假设当前
pHead
是B
,pHead->next
是C
,这行代码会递归调用ReverseList
,将从C
开始的子链表反转,并返回新的头节点ans
。 -
反转当前节点的指针:
pHead->next->next = pHead;
执行这行代码时,
pHead->next
是C
,pHead->next->next
原本是D
,现在被修改为pHead
,即B
。因此,C
的next
指针从D
变为B
。 -
断开当前节点的后继指针:
pHead->next = nullptr;
执行这行代码时,将当前节点
B
的next
指针设为nullptr
,因为它现在是新链表的末尾。
对反转部分代码进行示例讲解:
假设链表为 1 -> 2 -> 3 -> nullptr
,我们逐步应用递归和上述代码:
- 初始调用
ReverseList(1)
。 - 递归调用
ReverseList(2)
。 - 递归调用
ReverseList(3)
,返回3
,此时pHead
是3
。 - 回溯到
2
,此时pHead
是2
,pHead->next
是3
。执行pHead->next->next = pHead
,即3->next = 2
,变为2 <- 3
,并断开2
的后继指针,变为2 <- 3 -> nullptr
。 - 回溯到
1
,此时pHead
是1
,pHead->next
是2
。执行pHead->next->next = pHead
,即2->next = 1
,变为1 <- 2 <- 3 -> nullptr
,并断开1
的后继指针,变为1 <- 2 <- 3 -> nullptr
。
最终,链表反转为 3 -> 2 -> 1 -> nullptr
。