C语言题目练习2

前面我们知道了单链表的结构及其一些数据操作,今天我们来看看有关于单链表的题目~

移除链表元素

移除链表元素: https://leetcode.cn/problems/remove-linked-list-elements/description/

这个题目要求我们删除链表中是指定数据的结点,最终返回新的头结点,结合例子来看看。

示例1中删除了数据为6的结点,输出新的链表数据,我们可以怎么做呢?
首先来看看第一个方法

思路1

遍历链表找到值为val的结点,执行删除指定位置的操作,返回头结点

简单回顾单链表的删除pos结点操作我们可以进行更快的操作。

我们可以看到题目代码中已经给出了单链表的结构,只需要我们在函数中实现相应的操作就可以了。为了使用方便,我们可以将结构体使用typedef重命名一下:

cpp 复制代码
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val)
{
	ListNode* pcur = head;//遍历链表
	while(pcur)
	{
		//看是不是指定数据的结点
		//是就执行删除指定结点的操作
		if (pcur->val == val)
		{
			ListNode* pos = pcur;
			pcur = pcur->next;
             //易错点!!!
			//pcur直接往后面走,避免被释放
			if (pos == head)//头删
			{
				ListNode* next = pos->next;
				free(head);
				head = next;
				//原来头结点的下一个结点成为新的头结点
			}
			else
			{
				//遍历链表找指定结点的上一个结点
				ListNode* prev = head;
				while (prev->next != pos)
				{
					prev = prev->next;
				}
				//删除pos结点
				//改变上一个结点指向
				prev->next = pos->next;
				free(pos);
				pos = NULL;//释放及时置为空,避免野指针
			}
		}
		else
		{
			pcur = pcur->next;
		}//不是往后面继续遍历
	}
    //返回头结点
    //在原来的链表操作,头结点没有变化
	return head;
}

提交成功

这里有一个易错点就是当遍历到是指定数据的结点时,pcur要直接往后面走,用pos保存当前结点,这样能避免后面释放掉pcur,就不能正常使用了。
我们可以看到思路1有两层while循环,外层循环进行遍历找结点,内层循环删除指定的结点,那么时间复杂度也就是O(N^2),显然这不是最好的方案,我们有没有什么更好的方法呢?接下来,就是我们的思路二。

思路2

创建一个新的链表,遍历原来的链表,将链表中值不为val的结点尾插到新链表中,这个新链表呢,最开始创建两个新结点------NewHead、NewTail并且把它们置为空指针。

cpp 复制代码
typedef struct ListNode ListNode;
struct ListNode* removeElements(struct ListNode* head, int val)
{
	ListNode* NewHead = NULL;//新的头结点
	ListNode* NewTail = NULL;//新的尾结点

	//遍历原来的链表
	ListNode* pcur = head;
	while (pcur)//结点不为空
	{
		//将结点数据不等于val的放入新链表
		if (pcur->val != val)
		{
			//尾插
			//1.如果链表为空
			//新的头结点和尾结点就是当前的结点
			if (NewHead == NULL)
			{
				NewHead = NewTail = pcur;
			}
			//2.链表不为空
			else 
			{
				//新链表原来尾结点的下一个结点就是当前的结点
				NewTail->next = pcur;
				//当前结点成为新的尾结点
				NewTail = pcur;
			}
		}
		//继续往后面遍历
		pcur = pcur->next;
	}
	//易错点!!!
	//如果尾结点不为空,要把尾结点置为空
	if (NewTail)
	{
		NewTail->next = NULL;
	}
    //返回新的头结点
	return NewHead;
}

提交成功

这里有一个易错点就是要把尾结点的下一个结点置为空,如果不把尾结点的下一个结点置为空,尾结点本身的内容(保存的数据和下一个结点的指针)并没有发生改变,链表依然会带上尾结点后面的数据,比如示例1中1,2,6,3,4,5,6.当新的尾结点是5的时候,后面会带一个结点,而我们希望的是尾结点后面就没有结点了,所以我们要把尾结点的下一个结点置为空。当然,在置为空以前,首先要判断尾结点是否为空,避免对空指针进行解引用。

今日练习结束,期待与各位未来的优秀程序员交流,有什么请私信~~~

相关推荐
Ajiang282473530433 分钟前
对于C++中stack和queue的认识以及priority_queue的模拟实现
开发语言·c++
幽兰的天空38 分钟前
Python 中的模式匹配:深入了解 match 语句
开发语言·python
Theodore_10224 小时前
4 设计模式原则之接口隔离原则
java·开发语言·设计模式·java-ee·接口隔离原则·javaee
网易独家音乐人Mike Zhou4 小时前
【卡尔曼滤波】数据预测Prediction观测器的理论推导及应用 C语言、Python实现(Kalman Filter)
c语言·python·单片机·物联网·算法·嵌入式·iot
----云烟----6 小时前
QT中QString类的各种使用
开发语言·qt
lsx2024066 小时前
SQL SELECT 语句:基础与进阶应用
开发语言
开心工作室_kaic6 小时前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it6 小时前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康6 小时前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神7 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式