数据结构第三课 -----线性表之双向链表

作者前言

🎂 ✨✨✨✨✨✨🍧🍧🍧🍧🍧🍧🍧🎂
​🎂 作者介绍: 🎂🎂
🎂 🎉🎉🎉🎉🎉🎉🎉 🎂
🎂作者id:老秦包你会, 🎂
简单介绍:🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂🎂
喜欢学习C语言和python等编程语言,是一位爱分享的博主,有兴趣的小可爱可以来互讨 🎂🎂🎂🎂🎂🎂🎂🎂
🎂个人主页::小小页面🎂
🎂gitee页面:秦大大🎂
🎂🎂🎂🎂🎂🎂🎂🎂
🎂 一个爱分享的小博主 欢迎小可爱们前来借鉴🎂


双向链表

  • **作者前言**
  • 链表的差别
  • 带头双向循环链表的实现
    • 链表初始化
    • 节点创建
    • 链表的尾插
    • 链表尾删
    • 打印链表
    • 链表头插
    • 链表头删
    • 判断链表是否为空
    • 链表pos前插入
    • 计算链表长度
    • 链表删除pos前一个节点
    • 删除pos节点
    • 释放链表
    • 顺序表和链表的差异

链表的差别

在这里插入图片描述

  1. 无头单向非循环链表:结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结
    构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
  2. 带头双向循环链表:结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都
    是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带
    来很多优势,实现反而简单了,后面我们代码实现了就知道了。

带头双向循环链表的实现

在这里插入图片描述

我们需要的当这种链表为空时,
在这里插入图片描述
这个小知识一定要记住

链表初始化

DLists* plist = (DLists*)malloc(sizeof(DLists));
	plist->next = plist;
	plist->prev = plist;

一个节点要包含三部分分别是值,两个指针

节点创建

//创建节点
DLists* CreateNode(DLDataType elemest)
{
	DLists* newnode = (DLists*)malloc(sizeof(DLists));
	newnode->next = newnode;
	newnode->prev = newnode;
	newnode->val = elemest;
	return newnode;
}

链表的尾插

在这里插入图片描述

void DLPushBack(DLists* plist, DLDataType elelmest)
{
	assert(plist);
	//创建节点 
	DLists* newnode = CreateNode(elelmest);
	DLists* n = plist->prev;
	newnode->next = plist;
	newnode->prev = n;
	n->next = newnode;
	plist->prev = newnode;

}

这里我们只需要更改四个指针指向就可以,分别是哨兵位的 、prev 和新节点的prev 、next和旧节点的next

链表尾删

在这里插入图片描述

void DLPopBack(DLists* plist)
{
	assert(plist->next != plist && plist);
	//保存最后一个节点的地址
	DLists* p = plist->prev;
	plist->prev = p->prev;
	DLists* p1 = p->prev;
	p1->next = plist;
	free(p);
}

这样写可以防止只有一个节点的时候报错
我们可以创建两个指针,一个指向要free的节点,一个是要和哨兵位关联的节点也就是d2

打印链表

在这里插入图片描述
我们可以从d1这个节点开始打印,遇见头节点就结束

//打印
void DLPrint(DLists* plist)
{
	assert(plist);
	printf("哨兵位");
	DLists* tail = plist->next;
	while (tail != plist)
	{
		printf("<=>%d", tail->val);
		tail = tail->next;
	}
	printf("<=>哨兵位\n");
}

链表头插

在这里插入图片描述
我们可以创建一个指针用于存储d1的地址,然后把节点插入,这样可以简单快捷

//头插
void DLPushFront(DLists* plist, DLDataType elemest)
{
	assert(plist);
	DLists* n1 = plist->next;
	//创建节点
	DLists* newnode = CreateNode(elemest);
	plist->next = newnode;
	newnode->prev = plist;
	n1->prev = newnode;
	newnode->next = n1;
}

链表头删

在这里插入图片描述
当我们删除到哨兵位就不要删除了

//头删
void DLPopFront(DLists* plist)
{
	assert(plist->next != plist && plist);
	// 保存下一个节点
	DLists *nextnode = plist->next;
	DLists* nexnode_next = nextnode->next;
	plist->next = nexnode_next;
	nexnode_next->prev = plist;
	free(nextnode);
	
}

判断链表是否为空

// 判断链表是否为空
bool Empty(DLists* plist)
{
	assert(plist);
	return plist->next == plist;
}

链表pos前插入

在这里插入图片描述

//在pos前面插入
DLists* DLPushbefore(DLists* plist, DLists* pos, DLDataType elemest)
{
	assert(plist);
	//创建节点
	DLists* newnode = CreateNode(elemest);
	//pos的前一个节点
	DLists* node = pos->prev;
	pos->prev = newnode;
	newnode->next = pos;
	newnode->prev = node;
	node->next = newnode;

}

计算链表长度

// 长度
int DLSize(DLists* plist)
{
	assert(plist);
	DLists* tail = plist->next;
	int size = 0;
	while (tail != plist)
	{
		size++;
		tail = tail->next;
	}
	return size;


}

链表删除pos前一个节点

//删除pos前一个节点
DLists* DLPopbefore(DLists* plist, DLists* pos)
{
	assert(plist && pos);
	assert(pos->prev != plist);
	//前一个节点
	DLists* n2 = pos->prev;
	//前前一个节点
	DLists* n1 = n2->prev;
	n1->next = pos;
	pos->prev = n1;
	free(n2);
}

删除pos节点

// 删除 pos节点
DLists* DLPop(DLists* plist, DLists* pos)
{
	assert(plist && pos);
	assert(pos!= plist);
	//pos前一个节点
	DLists* n2 = pos->prev;
	//pos后一个节点
	DLists* n1 = pos->next;
	n2->next = n1;
	n1->prev = n2;
	free(pos);
}

释放链表

在这里插入图片描述
从d1开释放,遇见head停止

//释放链表
void DLDestroy(DLists** plist)
{
	assert(*plist && plist);
	DLists* tail = (*plist)->next;
	while (tail != *plist)
	{
		DLists* node = tail;
		tail = tail->next;
		free(node);
	}
	free(*plist);
	*plist = NULL;

}

顺序表和链表的差异

在这里插入图片描述
链表的优势

  1. 任意位置插入和删除都是O(1),前提是知道位置
  2. 按需申请和释放

缺点问题
3. 下标随机访问不方便,物理空间不连续,O(n)
4. 链表不好排序

顺序表的问题
5. 头部插入或者中间插入删除效率低下,要移动数据
6. 空间不够要扩容,扩容会有一定消耗且可能存在一定的空间浪费.
7. 只适合尾插尾删

优势
支持下标的随机访问

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

用Java开发一个扫雷游戏

以下是用Java开发一个扫雷游戏的基本步骤&#xff1a; 创建一个窗口和画布&#xff0c;用来显示游戏界面。 创建一个游戏逻辑类&#xff0c;包含一些基本的操作&#xff0c;如生成地雷、计算周围地雷数量、打开方格等。 在画布上绘制游戏界面&#xff0c;包括格子、数字、地雷…

人工智能与大数据:驱动现代业务转型的双引擎

在当今数字化时代&#xff0c;人工智能&#xff08;AI&#xff09;和大数据已成为驱动业务和技术创新的关键力量。它们的结合不仅重塑了传统行业&#xff0c;也催生了新的商业模式和服务方式。 AI与大数据在零售行业的应用 在零售行业&#xff0c;AI和大数据的应用已经成为提…

《洛谷深入浅出进阶篇》 P2367语文成绩——差分

上链接&#xff1a;P2367 语文成绩 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P2367 上题干&#xff1a; 题目背景 语文考试结束了&#xff0c;成绩还是一如既往地有问题。 题目描述 语文老师总是写错成绩&#xff0c;所以当她修改成绩的…

三、Eureka注册中心

目录 一、作用及调用方式 二、搭建eureka注册中心 三、注册user-service和order-service 四、新增实例 五、服务拉取 六、总结 一、作用及调用方式 在服务提供者启动时&#xff0c;它会向eureka注册中心提供自己的信息&#xff0c;并每30秒进行一次刷新eureka注册中心保存…

golang中context使用总结

一、context使用注意事项 在使用context时&#xff0c;有一些需要注意的事项&#xff0c;以及一些与性能优化相关的建议&#xff1a; 避免滥用context传递数据&#xff1a;context的主要目的是传递请求范围的数据和取消信号&#xff0c;而不是用于传递全局状态或大量数据。滥用…

SARAS算法

SARAS算法 代码仓库:https://github.com/daiyizheng/DL/tree/master/09-rl Sarsa算法是一种强化学习算法&#xff0c;用于解决马尔可夫决策过程&#xff08;MDP&#xff09;问题。它是一种基于值函数的方法&#xff0c;可以用于学习最优策略。本文将介绍Sarsa算法的流程。 S…

汽车以太网IOP测试新利器

IOP测试目的 汽车以太网物理层IOP&#xff08;Interoperability &#xff09;测试&#xff0c;即测试被测对象以太网物理层之间的互操作性。用于验证车载以太网PHY能否在有限时间内建立稳定的链路&#xff1b;此外&#xff0c;还用于验证车载以太网PHY可靠性相关的诊断特性&am…

滚雪球学Java(63):Java高级集合之TreeSet:什么是它,为什么使用它?

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴——bug菌&#xff0c;今天又来给大家普及Java SE相关知识点了&#xff0c;别躲起来啊&#xff0c;听我讲干货还不快点赞&#xff0c;赞多了我就有动力讲得更嗨啦&#xff01;所以呀&#xff0c;养成先点赞后阅读的好…

Java Elasticsearch 按一定时间间隔(timeInterval)循环查询数据

最近有个需求&#xff0c;前端传入时间间隔&#xff0c;去elasticsearch按照时间间隔统计每个时间间隔内数据量。 public List<HashMap<String,Object>> getCount(RequestParam Integer time, RequestParam String selectedDatedTime) {SimpleDateFormat format n…

Karmada调度器

调度器就像一个发动机&#xff0c;如果没有了发动机输入动力&#xff0c;是无法正常运行的。就像 Kubernetes 的调度器&#xff0c;它会负责根据节点的资源状态、Pod 的运行状态&#xff0c;判断 Pod 是调度到怎样的集群节点上去。对于 Karmada 这样的多云能力的调度器来说&…

Webpack 性能优化 二次编译速度提升3倍!

本文作者为 360 奇舞团前端开发工程师 Rien. 本篇文章主要记录 webpack 的一次性能优化。 现状 随着业务复杂度的不断增加&#xff0c;项目也开始变得庞大&#xff0c;工程模块的体积也不断增加&#xff0c;webpack 编译的时间也会越来越久&#xff0c;我们现在的项目二次编译的…

【fbtft】如何添加fbtft驱动

获取lcd ic的datasheet&#xff0c;或者直接找到其他平台&#xff08;linux&#xff0c;stm32&#xff0c;esp32&#xff09;的驱动 我用的是合宙的esp32驱动&#xff0c;注意是c语言的&#xff0c;合宙上层用lua封装了&#xff0c;需要找到sdk源码。 源码路径&#xff1a; …

2021年09月 Scratch(一级)真题解析#中国电子学会#全国青少年软件编程等级考试

一、单选题(共25题,每题2分,共50分) 第1题 如下图所示,小明想要做一个文字逐字出现的动画效果,他画出了程序的流程图,以下哪个程序可以实现? A: B: C: D: 答案&#

代号:408 —— 1000道精心打磨的计算机考研题

文章目录 &#x1f4cb;前言&#x1f3af;计算机科学与技术专业介绍&#xff08;14年发布&#xff09;&#x1f9e9;培养目标&#x1f9e9;毕业生应具备的知识和能力&#x1f9e9;主要课程 &#x1f3af;代号&#xff1a;408&#x1f525;文末送书&#x1f9e9;有什么优势&…

干货 | Elasticsearch 8.11 ES|QL 初体验

这里没有理论&#xff0c;只有验证后的结论和体验。 前提&#xff1a;这是 8.11 版本的新功能&#xff0c;必须提前安装最新 8.11 版本。 1、对比参考实现 1.1 DSL 原始语法 POST kibana_sample_data_ecommerce/_search 1.2 ES|QL 检索语法&#xff0c; 类似SQL实现 POST /_que…

2023亚太杯数学建模思路 - 复盘:人力资源安排的最优化模型

文章目录 0 赛题思路1 描述2 问题概括3 建模过程3.1 边界说明3.2 符号约定3.3 分析3.4 模型建立3.5 模型求解 4 模型评价与推广5 实现代码 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 1 描述 …

机器学习—基本术语

目录 1.样本&#xff08;示例&#xff09; 2.属性 3.属性值 4.属性空间 5.样本空间 6.学习&#xff08;训练&#xff09; 7.数据集 8.测试 9.假设 10.学习器 11.标记 12.样例 13.标记空间&#xff08;样例空间&#xff09; 14.分类与回归 15.有监督学习、无监督…

GZ038 物联网应用开发赛题第5套

2023年全国职业院校技能大赛 高职组 物联网应用开发 任 务 书 &#xff08;第5套卷&#xff09; 工位号&#xff1a;______________ 第一部分 竞赛须知 一、竞赛要求 1、正确使用工具&#xff0c;操作安全规范&#xff1b; 2、竞赛过程中如有异议&#xff0c;可向现场考评…

城市内涝对策,万宾科技内涝积水监测仪使用效果

随着城市化进程的加速&#xff0c;城市道路积水问题明显越来越多&#xff0c;给人们的出行和生活带来更多的不便。内涝积水监测仪作为高科技产品能够实时监测道路积水情况&#xff0c;为城市排水系统的管理和维护提供重要的帮助。 在城市生命线的基础设施规划之中&#xff0c;地…

Spring Cloud

1. 服务拆分和远程调用 任何分布式架构都离不开服务的拆分&#xff0c;微服务也一样。服务拆分&#xff1a;一个单体架构按照功能模块进行拆分&#xff0c;变成多个服务。 微服务需要根据业务模块拆分&#xff0c;做到单一职责&#xff0c;不要重复开发相同业务。 1.1 服务…