数据结构中的双向链表

news2024/9/20 0:50:16

1.链表的分类

链表的结构非常多样,以下情况组合起来就是8种(2x2x2)链表结构:

 

 在带头链表中,除了头结点,其他结点均存储有效的数据。

头结点是占位子的,也叫做“哨兵位”。head结点就是头结点。

 循环的链表尾结点不为NULL, 不循环的链表尾结点为NULL

单链表:不带头单向不循环链表

双向链表:带头双向循环链表

双向链表结构相较于单链表来说要复杂一些,但是接口的实现上要比单链表简单很多

双向链表的结点结构:数据+指向下一个结点的指针+指向前一个结点的指针

struct ListNode
{
  int date;
  struct ListNode *next;
  struct ListNode *prev;

}

 2.双向链表的实现

2.1头结点的创建

//创建头节点
LTNode* LTBuyNode(LTDateType x)
{
	LTNode* newnode = (LTNode*)malooc(sizeof(LTNode);
	if (newnode == NULL)
	{
		perror("malloc fail");
		exit(1);
	}
	newnode->date = x;
	//因为是双向循环,要循环起来,所以头结点要自己指向自己。
	newnode->next = newnode->prev = newnode;
}


//初始化
void LTInit(LTNode** pphead)
{
	//创建一个头结点
	*pphead = LTBuyNode(-1);
}

双向链表为空的情况就是只有一个头结点

2.2插入

传的是一级指针还是二级指针要看pphead指向的结点会不会发生改变,也就是头结点会不会发生改变。

如果发生改变,那么pphead的改变要影响实参,传二级

如果不发生改变,pphead不会影响实参,传一级。

2.2.1尾插

尾插影响的是尾插前一个结点和头结点,改变他们的指向就好了。

先修改插入的结点的指向,比较方便

//插入
//传的是一级指针还是二级指针要看pphead指向的结点会不会发生改变,也就是头结点会不会发生改变。
//如果发生改变,那么pphead的改变要影响实参,传二级
//如果不发生改变,pphead不会影响实参,传一级。
//尾插
void LTPushBack(LTNode* pphead, LTDateType x)
{
    assert(pphead);
	LTNode* newnode = LTBuyNode(x);
	//pphead pphead->prev newnode
	newnode->next = pphead;
	newnode->prev = pphead->prev;

	pphead->prev->next = newnode;
	pphead->prev = newnode;
}

2.2.2头插

头插是在哨兵位与第一个有效结点之间插入数据,不是在哨兵位前插入数据,在哨兵位前插入数据是尾插。

受到影响的有哨兵位,第一个有效节点,还是先改插入newnode的指向。

 

void LTPushFront(LTNode* phead, LTDateType x)
{
	assert(phead);

	LTNode* newnode = LTBuyNode(x);

	//phead newnode phead->next
	newnode->next = phead->next;
	newnode->prev = phead;

	phead->next->prev = newnode;
	phead->next = newnode;

}

2.3双向链表的打印

双向链表的死循环的,为了让他不死循环,结束条件可以是不等于哨兵位。

//打印
void LTprint(LTNode* phead)
{
	LTNode* pcur = phead->next;
	while (pcur!=phead)
	{
		printf("%d->", pcur->date);
		pcur = pcur->next;
	}
	printf("\n");
}

2.4判断链表是否为空

//判断链表是否为空
bool LTEmpty(LTNode* phead)
{
	assert(phead);
	//返回true表示链表为空,返回false表示链表不为空
	//非0表示true,0表示false。
	//如果phead->next == phead,返回1
	//如果phead->next != phead,返回0
	return phead->next == phead;
}

2.5删除

不要把哨兵位删除,不会影响哨兵位,一级指针。

还要判断一下链表不为NULL,不然没东西删。

2.5.1尾删

思路:影响到的有尾结点的前一个结点以及哨兵位的结点,改变他们的指向,然后释放尾结点

void LTPopBack(LTNode* phead)
{
	assert(phead);
	//判断链表是否为NULL
	assert(!LTEmpty(phead));

	//phead prev(del->prev) del(phead->prev)
	LTNode* del = phead->prev;
	LTNode* prev = del->prev;

	prev->next = phead;
	phead->prev = prev;

	free(del);
	del = NULL;

}

2.5.2头删

头删删的是哨兵位后面的结点,

//头删
void LTPopFront(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));

	//phead del(phead->next) del->next
	LTNode* del = phead->next;
	del->next->prev = phead;
	phead->next = del->next;
	 
	free(del);
	del = NULL;
}

2.6查找

//查找
LTNode* LTFind(LTNode* phead, LTDateType x)
{
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		if (pcur->date == x)
		{
			return pcur;
		}
		pcur = pcur->next;
	}
	return NULL;
}

2.7在指定位置(pos)之后插入节点

先改变newnode的指向,再改相邻的指向

 

//在指定位置(pos)之后插入节点
void LTInsert(LTNode* pos, LTDateType x)
{
	assert(pos);

	LTNode* newnode = LTBuyNode(x);

	//pos pos->prev pos->next
	newnode->prev = pos;
	newnode->next = pos->next;

	pos->next->prev = newnode;
	pos->next = newnode;

}

2.8删除指定位置的结点

//删除指定位置的结点
void LTErase(LTNode* pos)
{
	assert(pos);

	//pos pos->prev pos->next
	pos->prev->next = pos->next;
	pos->next->prev = pos->prev;

	free(pos);
	pos = NULL;

}

2.9销毁

二级指针,因为会影响到哨兵位。

从第一个有效的结点开始销毁。

//销毁
void LTDesTroy(LTNode** pphead)
{
	assert(pphead && *pphead);
	LTNode* pcur = (*pphead)->next;
	while (pcur!=*pphead)
	{
		LTNode* Next = pcur->next;
		free(pcur);
		pcur = Next;
	}
	free(*pphead);
	*pphead = NULL;
	pcur =	NULL;

}

2.10初始化和销毁也可以是一级指针

这样做的目的是为了保证接口的一致性

1.销毁的一级指针

要在.h文件中手动置为NULL

//销毁
void LTDesTroy2(LTNode* phead)
{
	assert(phead);
	LTNode* pcur = phead->next;
	while (pcur != phead)
	{
		LTNode* Next = pcur->next;
		free(pcur);
		pcur = Next;
	}
	free(phead);
	pcur = phead = NULL;
}

2.初始化的一级指针

//初始化
LTNode* LTInit2()
{
	LTNode* phead = LTBuyNode(-1);
	return phead;
}

 第1种方法要提前弄一个plist变量,传他的地址才能调用

第二种可以直接调用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2056357.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【实战场景】如何优雅实现分页

【实战场景】如何优雅实现分页 开篇词:干货篇:1.添加PageHelper依赖2.添加PageHelper配置3.使用 PageHelper4.自定义Pageable注解 总结:1.执行查询2.处理分页结果3.注意事项 我是杰叔叔,一名沪漂的码农,下期再会&#…

代码随想录算法训练营day49 | 42. 接雨水、84.柱状图中最大的矩形

碎碎念: 参考:代码随想录 42. 接雨水 题目链接 42. 接雨水 思想 如图可以按照列来计算,这样宽度一定是1,只需要计算每一列的雨水的高度接口。而每一列的雨水高度取决于该列左侧最高的主子和右侧最高柱子中最矮的那个柱子的高度…

如何使用Java SpringBoot+Vue搭建半成品配菜平台,实现家庭烹饪新体验

✍✍计算机毕业编程指导师 ⭐⭐个人介绍:自己非常喜欢研究技术问题!专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目:有源码或者技术上的问题欢迎在评论区一起讨论交流! ⚡⚡ Java、…

用Python编写一个超级玛丽游戏|附源码

​ 编写一个超级玛丽游戏是一个复杂的任务,涉及到多个方面的编程知识和技巧。下面,我将详细讲解如何用Python编写一个简化版的超级玛丽游戏,包括所需的库、游戏逻辑、角色控制、关卡设计、碰撞检测等方面。 所需库 为了编写这个游戏&#…

猫咪去浮毛能一劳永逸吗?手动不行宠物空气净化器是真能做到

现在啊,越来越多的家庭选择养宠物来增添生活乐趣。但宠物带来的快乐背后,也有那么点“小困扰”:下班回家,迎接你的可能是满屋子的“特殊香味”和无处不在的毛发。这样的环境,真的不会对我们的健康产生不良影响吗&#…

照片整理专家,照片整理大师,照片图库整理,智能图片整理软件

前言 业务痛点: 就是我从2015年拥有自己的智能手机之后,就会刻意的对自己拍过的照片、视频,收藏的视频等,媒体元素,进行收集归纳,尝试过很多的存储方案,归纳整理方案 2015年 百度网盘 2016年 时…

电子厂车间的客流统计需要集成哪些硬件设备

在电子厂车间中,准确的客流统计对于生产管理和安全保障至关重要。要实现有效的客流统计,需要集成一系列硬件设备。 首先,客流统计系统主要由以下硬件组成。一是人数采集设备,通常采用红外传感器、双目摄像头等,安装在车…

【时时三省】(C语言基础)数据的额存储

山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 例题1: i>0恒成立 会进入死循环 因为unsigned是无符号数 所以不可能会有负数 就会进入死循环 注意:i打印的时候如果它上面类型是无符号数 但是打印是%d 它会打印有符号数 例题:2 这个循…

【Python开发实践】AI人机对战五子棋——程序调用及运行效果

主函数调用: if __name__ __main__:game Game(version)while True:game.play()pygame.display.update()for event in pygame.event.get():if event.type pygame.QUIT:pygame.quit()exit()elif event.type pygame.MOUSEBUTTONDOWN:mouse_x, mouse_y pygame.mou…

基于opencv 纹理图/枯叶图 MTF/ACUTANCE评测算法

1.有SFR算法为何还要引入基于纹理图的MTF/ACUTANCE评测算法? 如果使用的raw数据,只用sfr测试不同频率的mtf是完全可以的。但如果经过isp处理后,因为存在降噪/锐化处理,并不能真正体现纹理和边缘的实际表现。 例如: 在相…

手机运动信息管理系统

目录 一:案例要求: 二:代码:(多文件形式) 1:main.h 2 main.cpp 3 menu.cpp(这个可以拆开写在每一个.cpp里面) 4 功能1用户信息的增删改查.h 5功能1用户信息的增删改查.cpp 6功能2运动信息管理.h 7功能2运动信息…

鸿蒙(API 12 Beta3版)【DRM Kit 简介】数字版权保护

开发者通过调用DRM Kit(Digital Rights Management Kit,数字版权保护服务)提供的接口可以开发播放器应用,实现数字版权保护的基础操作,如设备证书管理、许可证管理、解密操作等;还可以通过接口参数配置完成…

亚马逊铺货ERP国内采集,图片编辑文本翻译一键拉伸,自...

亚马逊全功能 ERP 铺货采集,自动生成 SKU。 说说国内平台采集的商品如何通过 ERP 自己做链接上传发布到亚马逊平台! 1. 首先进入 ERP 插件,直接点击 1688 平台采集自己想做的产品类型。各位按照自身的需求选择搜索的 JK,选择想采…

AI小白福音来啦~Flux文生图,支持手部细节,直出精美图像,让你瞬间变高手!

国产AI绘画软件在近年来发展迅速,其中千鹿设计助手的“Flux 文生图”插件受到了用户的关注。根据搜索结果,Flux文生图插件以其强大的功能和易用性,为设计师提供了便捷的服务。以下是关于Flux文生图插件的测评和使用指南: 工具准备…

【Hot100】LeetCode—160. 相交链表

目录 1- 思路思路 2- 实现⭐160. 相交链表——题解思路 3- ACM 实现 原题连接:160. 相交链表 1- 思路 思路 首先想要找到相交点,需要定义连个指针。两个指针一定得是同步的,例如 A 链表 [1,2,3,4,5] ,链表 B 是 [4,5] 1- 指针对…

<Qt> 界面优化

目录 前言: 背景介绍 一、QSS基本语法 二、QSS设置方式 (一)指定控件样式设计 (二)全局样式设置 (三)从文件加载样式表 (四)Qt Designer 编辑样式 三、选择器 …

​​JVM三:JVM垃圾回收机制(GC)

1.什么是垃圾? 指的是不再使用的内存。 2.垃圾回收 将不用的内存,自动释放,解决内存泄露问题。 3.GC主要针对堆进行释放 GC是以"对象"为基本单位,进行回收,而不是字节。 垃圾回收(GC)主要处理三…

刑事拘留和逮捕在程序上有何区别?

1. 实施条件:刑事拘留是在有重大犯罪嫌疑且存在逃避侦查、串供或者其他妨碍刑事诉讼行为可能的情况下,由公安机关决定采取的临时剥夺人身自由的强制措施。而逮捕则是更为严厉的强制措施,通常在犯罪嫌疑人涉嫌的重大犯罪事实已经查清&#xff…

【贝壳找房】测试开发一面凉经--北京现场面(附面试答案)

1.单链表反转写 单链表是一种线性结构,它是由一个个节点(Node)组成的。并且每个节点(Node)是由一块数据域(data)和一块指针域(next)组成。 节点的数据域:da…

vue element-plus el-drawer 自定义抽屉标题 template slot动态标题定义方法

默认抽屉定义&#xff0c; 这里的title就是标题的定义 <el-drawer v-model"drawer" title"I am the title" :direction"direction" :before-close"handleClose" > 如果我们需要自定义这个标题&#xff0c;就需要使用slot <e…