数据结构——双向链表及其总结

news2025/1/10 10:25:20

1.概述

链表根据是否带头、是否双向、是否循环可以分为八种,双向链表是典型的带头双向循环链表。

双向链表的结构可以表示为下:

struct ListNode
{
    int data;
    struct ListNode* next;
    struct ListNode* prev;
}

2.双向链表的实现过程及其解析

双向链表的实现依旧包含List.h,List.c,test.c

2.1 链表初始化

双向链表为空的情况:只有一个哨兵位。

先定义一个结构如下:

typedef int LTDatatype;
typedef struct ListNode {
	LTDatatype data;
	struct ListNode* next;
	struct ListNode* prev;
}LTNode;

链表初始化时我们应该先创建一个哨兵位,则实现代码如下:

LTNode* LTBuyNode(LTDatatype x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		perror("malloc fail!");
		exit(1);
	}
	newnode->data = x;
	newnode->next = newnode;
	newnode->prev = newnode;

	return newnode;
}
//初始化
void LTInit(LTNode** pphead)
{
	//创建一个哨兵位
	*pphead = LTBuyNode(-1);
}

2.2插入数据

2.2.1 尾插

 因为在双向链表中有哨兵位,所以在这种情况下不用二级指针,用一级指针就可以实现。

用一级还是二级,要看pphead指向的结点会不会改变,如果发生改变,传二级,如果不发生改变,要传一级。

尾插时发生改变的是头结点和最后一个结点。

第一个结点:第一个有效的结点。

哨兵位:头结点。

代码实现如下:

//插入数据
//尾插
void LTPushBack(LTNode* phead, LTDatatype x)
{
    assert(phead);
	LTNode* newnode = LTBuyNode(x);
	//从后往前
	newnode->next = phead;
	newnode->prev = phead->prev;

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

2.2.2 头插

打印链表的代码:

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

头插的代码实现:

//头插
void LTPushFront(LTNode* phead, LTDatatype x)
{
	assert(phead);
	//相当于插入哨兵位之后
	LTNode* newnode = LTBuyNode(x);

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

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

 2.3 判断链表是否为空

//判断链表是否为空
bool LTEmpty(LTNode* phead)
{
	assert(phead);
	return phead->next == phead;
}

2.4 删除数据

2.4.1 尾删

//删除数据
//尾删
void LTPopBack(LTNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));

	LTNode* del = phead->prev;
	LTNode* prev = del->prev;

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

	free(del);
	del = NULL;
}

 2.4.2 头删

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

	LTNode* del = phead->next;
	del->next->prev = phead;
	phead->next = del->next;

	free(del);
	del = NULL;
}

2.5 查找 

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

 2.6 在指定位置之后插入数据

//在指定位置之后插入数据
void LTInsert(LTNode* pos, LTDatatype x)
{
	assert(pos);
	LTNode* newnode = LTBuyNode(x);

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

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

 2.7 删除指定位置数据

//删除指定位置结点
void LTErase(LTNode* pos)
{
	assert(pos);
	pos->prev->next = pos->next;
	pos->next->prev = pos->prev;

	free(pos);
	pos = NULL;
}

 2.8 销毁链表

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

2.9 代码改善 

在我们写代码时我们总是要考虑传二级指针,还是一级指针,那么有没有什么方法可以进行改进呢?

2.9.1 改进销毁链表的代码 

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

 传一级时,需要手动将plist置为NULL。

2.9.2  改进初始化的链表

LTNode* LTInit1()
{
	LTNode* phead = LTBuyNode(-1);
	return phead;
}

在调用时应该用:

//调用时为
LTNode* plist = LTInit1();

 

 3.总结

(该图片来自比特就业课的课件) 

在图中我们可以分别出顺序表和链表之间的关系,我们要重点关注其应用场景。

今天就到这里,我们下一个知识点见(* ̄︶ ̄)!

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

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

相关文章

Redis 内存淘汰策略

Redis 作为一个内存数据库,必须在内存使用达到配置的上限时采取策略来处理新数据的写入需求。Redis 提供了多种内存淘汰策略(Eviction Policies),以决定在内存达到上限时应该移除哪些数据。

如何理解Java的内存模型

希望文章能给到你启发和灵感~ 如果觉得文章对你有帮助的话,点赞 + 关注+ 收藏 支持一下博主吧~ 阅读指南 开篇说明一、内存相关基础了解1.1 硬件的内存架构1.2 缓存一致性问题1.3 内存模型的出现二、Java内存模型2.1 组成部分2.2 模型特性2.4 As-if-serial语义与Happens-bef…

【2024蓝桥杯/C++/B组/前缀总分】

题目 代码 #include<bits/stdc.h> using namespace std;// 定义常量N为210&#xff0c;用于数组的大小 const int N 210; // 声明n为整型变量&#xff0c;用于存储字符串的数量 int n; // 声明一个字符串数组str&#xff0c;大小为N&#xff0c;用于存储字符串 string …

pda条码扫描手持机,数据采集器助力景区售检票

随着科技的发展&#xff0c;景区也在往信息化方向发展&#xff0c;景区为了提升售票、检票入园效率&#xff0c;可采用pda条码扫描手持机售检票系统。pda条码扫描手持机是一种便携式的检票设备&#xff0c;可以随时随地使用。配备5.5寸高清大屏,1440*720分辩率&#xff0c;多点…

安防监控视频融合汇聚平台EasyCVR创建新用户时没有摄像机权限,是什么原因?

国标GB28181/RTSP/ONVIF视频管理系统EasyCVR视频汇聚平台&#xff0c;是一个具备高度集成化、智能化的多协议接入视频监控汇聚管理平台&#xff0c;拥有远程视频监控、录像、云存储、录像检索与回放、语音对讲、云台控制、告警、平台级联等多项核心功能。EasyCVR安防监控视频系…

docker笔记5-数据卷

docker笔记5-数据卷 一、数据卷1.1 定义1.2 本质1.3 特点 二、使用数据卷三、案例2.1 安装Mysql 四、匿名挂载和具名挂载4.1 匿名挂载4.2 具名挂载 五、三种挂载方式 一、数据卷 1.1 定义 Docker 容器数据卷是一个可用于存储数据的特殊目录&#xff0c;存在于一个或多个容器的…

免费【2024】springboot 出租车管理网站的设计与实现

博主介绍&#xff1a;✌CSDN新星计划导师、Java领域优质创作者、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和学生毕业项目实战,高校老师/讲师/同行前辈交流✌ 技术范围&#xff1a;SpringBoot、Vue、SSM、HTML、Jsp、PHP、Nodejs、Python、爬虫、数据可视化…

unity2D游戏开发15自我防御

创建子弹 Ammo类来表示自子弹 创建一个GameObject,并命名为AmmoObject 将Ammo.png拖入Object中 属性设置,点击apply 将SpriteRenderer组件添加到AmmoObject,将Sorting Layer设置为Characters,并将Sprite属性设置为Ammo 将CircleCollider2D添加到AmmoObject。确保选中Is Tr…

【C++高阶】哈希的应用(封装unordered_map和unordered_set)

✨ 世事漫随流水&#xff0c;算来一生浮梦 &#x1f30f; &#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;C学习 &#x1f680; 欢迎关注&#xff1a;&#x1f44d;点赞 &#x1f442;&…

KubeSphere部署:(三)MySQL安装

MySQL没有什么特殊的&#xff0c;这里记录一下部署过程(本文示例中安装的版本为5.7.29)。步骤大致如下&#xff1a; 拉取docker镜像 -> 标记并推送至私有harbor -> 创建有状态负载 -> 创建服务 一、拉取镜像&#xff0c;并推送至私有harbor # 拉取镜像 docker pull …

PP氮气柜的特点和使用事项介绍

PP材质&#xff0c;全称为聚丙烯&#xff0c;是一种热塑性塑料&#xff0c;具有质轻、强度高、耐化学腐蚀性好、无毒无味、耐热性佳等优点。它在众多塑料材料中脱颖而出&#xff0c;特别是在需要耐腐蚀和长期使用的应用中&#xff0c;表现尤为出色。 PP材质具有优秀的化学稳定性…

Loadrunner12 回放脚本查看接口响应数据

1、如下图所示&#xff0c;回放脚本后&#xff0c;点击快照-http数据-点击需要查看的接口-点击Json视图&#xff0c;最后点击响应正文&#xff0c;即可查看接口的响应数据

生信初学者教程(癌症转录组学):手把手教你如何发生信文章

网址 生信初学者教程&#xff08;癌症转录组学&#xff09; : https://bioinformatic-learner.github.io/BCT-page/ 提供了预览版本。 该教程包含从开题、数据下载、数据分析、结果解读、串联结果和撰写文章等等&#xff0c;是一份非常好的生信初学者发文章的好材料。 出发点…

【Linux】UDP 协议

目录 1. UDP 协议2. UDP 协议的特点:3. UDP 协议的格式4. UDP 的缓冲区基于UDP的应用层协议 1. UDP 协议 UDP (User Datagram Protocol) 是一种面向数据报的传输层协议, 是传输层的重要协议之一; UDP协议提供了一种无连接, 不可靠的数据传输服务; 适用于要求源主机以恒定速率…

响应式建站陶瓷企业类公司网站源码系统 带完整的安装代码包以及搭建部署教程

系统概述 响应式建站陶瓷企业类公司网站源码系统是一款专为陶瓷企业设计的网站建设解决方案。该系统采用响应式设计&#xff0c;能够自动适应不同设备的屏幕尺寸&#xff0c;为用户提供一致的浏览体验。无论用户是通过电脑、平板还是手机访问网站&#xff0c;都能获得清晰、美…

html+css 实现3D分层悬停按钮

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 文…

太牛了!恭喜7位毕业急录、评职晋升作者,2天录用,1-8天见刊!

本周投稿推荐 SCI&EI • 4区“水刊”&#xff0c;纯正刊&#xff08;来稿即录&#xff09; • CCF-B类&#xff0c;IEEE一区-Top&#xff08;3天初审&#xff09; EI • 各领域沾边均可&#xff08;2天录用&#xff09; 知网&#xff08;CNKI&#xff09;、谷歌学术 …

posthog,一个超酷的 Python 库!

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 大家好&#xff0c;今天为大家分享一个超酷的 Python 库 - posthog。 Github地址&#xff1a;https://github.com/PostHog/posthog 在现代数据驱动的开发过程中&#xff0c;了解用户行为和应用性能是至关重要的…

this关键字的简明指南与理解

this关键字是执行上下文中的一个属性&#xff0c;它主要用在函数内部&#xff0c;指向最后一次调用该函数的对象。然而&#xff0c;this 的值并不是在函数定义时确定的&#xff0c;而是在函数被调用时根据函数的调用方式动态绑定的。以下是对 this 的一些相关理解。 一、this的…

Scrapy 爬取旅游景点相关数据(七):利用指纹实现“不重复爬取”

本期学习&#xff1a; 利用网页指纹去重 众所周知&#xff0c;代理是要花钱的&#xff0c;那么在爬取&#xff08;测试&#xff09;巨量网页的时候&#xff0c;就不可能对已经爬取过的网站去重复的爬&#xff0c;这样会消耗大量的时间&#xff0c;更重要的是会消耗大量的IP (金…