牛客网在线编程题练习1——单链表反转

在上节中练习了创建一个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 时,当前节点 pHeadBpHead->nextCpHead->next->nextD。我们希望将节点 Cnext 指针指向 B,从而反转这两个节点之间的指向关系。

通过执行 pHead->next->next = pHead;,我们改变了链表的结构,使得 Cnext 指针指向 B

A -> B <- C -> D -> nullptr

为了更好地理解这行代码,我们来看一下递归的上下文。在 ReverseList 函数中,递归逐步反转每个节点与其后继节点之间的关系。以下是一个详细的分步解释:

  1. 递归反转后续节点

    ListNode* ans = ReverseList(pHead->next);

    假设当前 pHeadBpHead->nextC,这行代码会递归调用 ReverseList,将从 C 开始的子链表反转,并返回新的头节点 ans

  2. 反转当前节点的指针

    pHead->next->next = pHead;

    执行这行代码时,pHead->nextCpHead->next->next 原本是 D,现在被修改为 pHead,即 B。因此,Cnext 指针从 D 变为 B

  3. 断开当前节点的后继指针

    pHead->next = nullptr;

    执行这行代码时,将当前节点 Bnext 指针设为 nullptr,因为它现在是新链表的末尾。

对反转部分代码进行示例讲解:

假设链表为 1 -> 2 -> 3 -> nullptr,我们逐步应用递归和上述代码:

  1. 初始调用 ReverseList(1)
  2. 递归调用 ReverseList(2)
  3. 递归调用 ReverseList(3),返回 3,此时 pHead3
  4. 回溯到 2,此时 pHead2pHead->next3。执行 pHead->next->next = pHead,即 3->next = 2,变为 2 <- 3,并断开 2 的后继指针,变为 2 <- 3 -> nullptr
  5. 回溯到 1,此时 pHead1pHead->next2。执行 pHead->next->next = pHead,即 2->next = 1,变为 1 <- 2 <- 3 -> nullptr,并断开 1 的后继指针,变为 1 <- 2 <- 3 -> nullptr

最终,链表反转为 3 -> 2 -> 1 -> nullptr

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值