数据结构:带头双向循环链表的实现

news2024/11/17 16:03:51

引言

单链表存在缺陷:需要从头开始找前一个节点

解决方法:双向链表

链表的结构(8种):

1. 单向,双向

2. 带头、不带头

  • 带头即为带哨兵位的头节点,第一个节点不存储有效数据。
  • 带头节点,不需要改变传过来的指针,也就是意味着不需要传二级指针了,因为不管是头删还是尾删都不会改变头结点的位置,故不用二级指针进行传参。
  • 做好不要用头节点存链表的长度

3. 循环,非循环

之前说的链表里最后一个节点指向空指针,循环链表里最后一个结点指向第一个结点的地址

链表结构可分为单向带头循环,单向不带头循环,将以上三类进行排列组合可得2*2*2=8种链表结构

这里我就说一下带头双向循环链表吧

图示方框为头节点,不添加任何有效数据,头节点的前驱指向3的位置,3的后驱指向头节点,图示就是带头双向循环链表了

我们先来简单实现带头双向循环链表吧

带头双向循环链表的初始化

将头节点的前驱和后驱均指向自己。

typedef double LTDataType;
typedef struct ListNode
{
	struct ListNode* next;
	struct ListNode* prev;
	int data;
}ListNode;
ListNode* ListInit();
//创建一个结点
ListNode* BuyListNode(LTDataType x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	newnode->data = x;
	newnode->prev = NULL;
	newnode->next = NULL;
    return newnode;
}
初始化链表
ListNode* ListInit()
{
	ListNode* phead = BuyListNode(0);
	phead->data = phead;
	phead->prev = phead;
	return phead;
}

带头双向循环链表的尾插:

双向循环链表可直接通过头节点找到尾节点,

将尾节点的next指向新建节点,

新建节点prev指向最初尾节点,

新建节点的next的指向头节点,

头节点的prev指向新建节点。

//尾插
void ListPushBack(ListNode* phead, LTDataType x) 
{
	//无论链表是否为空,均可尾插
	ListNode* tail = phead->prev;
	ListNode* newnode = BuyListNode(x);
	newnode->prev=tail;
	newnode->next = phead;
	phead->prev = newnode;

}

 带头双向链表的输出:

遍历整个链表,直到遍历到头节点(循环)

void ListPrint(ListNode* phead)
{
	assert(phead);//phead不能为空
	ListNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d ", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

带头双向链表的头删:

记录第一个和第二个节点的位置,

将头节点next指向第二个节点

,第二个节点的prev指向头节点即可完成头删。

void ListPopFront(ListNode* phead, LTDataType x) 
{
	assert(phead);
    assert(phead->next!=NULL);//保证无结点时不删除
	ListNode* first = phead->next;
	ListNode* second = first->next;
	phead->next = second;
	second->prev = phead;
	free(first);
	first = NULL;
}

带头双向链表的头插:

首先要记录第一个节点的位置,以防位置被覆盖

将头节点的next指向新建节点,

新建节点的prev指向头节点,

新建节点的next指向第一个节点,

第一个节点的prev指向新建节点。

void ListPushFront(ListNode* phead, LTDataType x)
{
	assert(phead);
	ListNode* first = phead->next;
	ListNode* newnode = BuyListNode(x);
	phead->next = newnode;
	newnode->prev = phead;
	newnode->next = first;
	first->prev = newnode;
}

带头双向链表的尾删:

记录左后一个节点以及倒数第二个节点的位置。

将倒数第二个节点的next指向头节点,

头结点的prev指向倒数第二个节点,

释放掉最后一个节点。

//尾删
void ListPopBack(ListNode* phead)
{
	assert(phead);
	assert(phead->next != NULL);//不可把头结构删除
	ListNode* tail = phead->prev;
	ListNode* prev = tail->prev;
	prev->next = phead;
	phead->prev = prev;
	free(tail);
	tail = NULL;
}

带头双向循环链表的查找:

 遍历链表直到遍历至头节点,若找到要找的值,就返回该地址,遍历完还没有找到就返回NULL

//查找
ListNode* ListFind(ListNode* phead, LTDataType x)
{
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
			return cur;
		cur=cur->next;
	}
	return NULL;
}

在带头双向链表的某个节点前插入新的结点:

记录插入位置的前一个位置,

新建链表的prev指向前一个链表,

前一个链表的next指向新建链表,

新建链表的next指向插入位置

,插入位置的prev指向前一个位置。

// 在pos之前插入x
void ListInsert(ListNode* pos, LTDataType x)
{
	assert(pos);
	ListNode* prev = pos->prev;
	ListNode* newnode = BuyListNode(x);
	newnode->prev = prev;
	prev->next = newnode;
	newnode->next = pos;
	pos->prev = newnode;
}

 删除带头双向链表的某个结点:

记录删除结点位置的前一个节点位置以及后一个节点的位置

前一个节点的next指向后一个节点,

后一个节点的prev指向前一个节点

释放要删除节点的指针

//删除pos位置的值
void ListErase(ListNode* pos)
{
	assert(pos);
	ListNode* prev = pos->prev;
	ListNode* next = pos->next;
	prev->next = next;
	next->prev->prev;
	free(pos);
	pos=NULL;
}

释放掉整个链表:

 

遍历整个链表,注意在释放节点时,要先记录下一个节点,遍历完之后,释放头节点。

//释放链表
void ListDestory(ListNode* phead)
{
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
}

双向带头循环链表的特点,结构复杂,但操作简单

带头双向循环 -- 最优链表结构,任意位置插入删除数据空间复杂度都是0(1)。

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

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

相关文章

计算机网络——数据链路层-封装成帧(帧定界、透明传输-字节填充,比特填充、MTU)

目录 介绍 帧定界 PPP帧 以太网帧 透明传输 字节填充(字符填充) 比特填充 比特填充习题 MTU 介绍 所谓封装成帧,就是指数据链路层给上层交付下来的协议数据单元添加帧头和帧尾,使之成为帧。 例如下图所示: …

SQL注入漏洞的检测及防御方法

SQL注入(SQL Injection)是一种广泛存在于Web应用程序中的严重安全漏洞,它允许攻击者在不得到授权的情况下访问、修改或删除数据库中的数据。这是一种常见的攻击方式,因此数据库开发者、Web开发者和安全专业人员需要了解它&#xf…

主动学习入门Week1

主动学习(Active Learning) 介绍实例详解模型分类基本查询策略经典方法应用方向引用 介绍 主动学习是一种通过主动选择最有价值的样本进行标注的机器学习或人工智能方法。其目的是使用尽可能少的、高质量的样本标注使模型达到尽可能好的性能。也就是说&…

Docker容器间网络共享

Docker容器间网络共享 1、新建网络2、容器绑定网卡3、验证 Docker环境中为了一套应用部署多个环境、并且不修改配置文件的情况下,做到一键部署。要求不同容器直接的网络交互,使用容器名称。 网络相关常用命令 #查看网络内部信息docker network inspect b…

scrapy的建模及管道的使用

一、数据建模 通常在做项目的过程中,在items.py中进行数据建模 为什么建模 定义item即提前规划好哪些字段需要抓,防止手误,因为定义好之后,在运行过程中,系统会自动检查,配合注释一起可以清晰的知道要抓…

熬夜会秃头——beta冲刺Day4

这个作业属于哪个课程2301-计算机学院-软件工程社区-CSDN社区云这个作业要求在哪里团队作业—beta冲刺事后诸葛亮-CSDN社区这个作业的目标记录beta冲刺Day4团队名称熬夜会秃头团队置顶集合随笔链接熬夜会秃头——Beta冲刺置顶随笔-CSDN社区 一、团队成员会议总结 1、成员工作进…

scrapy框架

scrapy文档 文档链接 安装指南 — Scrapy 2.5.0 文档 (osgeo.cn)https://www.osgeo.cn/scrapy/intro/install.html 创建scrapy框架 0.介绍: scrapy是异步非阻塞框架 异步:一个主线程有20个任务,可以来回切换 非阻塞:运行的程序不需…

vue项目引入外部vue项目页面

vue项目使用iframe引入外部项目页面 vue项目引入外部项目页面有好几种方法&#xff0c;我这种使用的是iframe 示例 <template><div><iframe:src"userPageUrl"width"100%"height"800"frameborder"0"allowfullscreen&…

导入seaborn的数据集方法load_datasets的问题

sns.load_dataset使用报错解决URLError: &#xff1c;urlopen error [Errno 11004] getaddrinfo failed&#xff1e;&#xff08;windows&#xff09;&#xff09; import seaborn as sns import matplotlib.pyplot as plt ​ # 使用Seaborn自带的数据集 tips sns.load_datas…

(C++)有效三角形的个数--双指针法

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台备战技术面试&#xff1f;力扣提供海量技术面试资源&#xff0c;帮助你高效提升编程技能&#xff0c;轻松拿下世界 IT 名企 Dream Offer。https://le…

【科技素养】蓝桥杯STEMA 科技素养组模拟练习试卷14

单选题 1、下列现象中有化学变化发生的是 A、蜡烛融化 B、冰块融化 C、电磁炉烧开水 D、铁生锈 答案&#xff1a;D 2、把左边的图形用剪刀剪开&#xff0c;拼成右边的正方形&#xff0c;至少剪几刀 A、1 B、2 C、3 D、4 答案&#xff1a;B 3、能够检验土壤中有沙和粘…

中国毫米波雷达产业分析6——毫米波雷达行业发展展望

一、行业发展驱动力分析 &#xff08;一&#xff09;需求带动 当前&#xff0c;全球智能化变革浪潮正在汽车、交通、安防、工业、家居、健康监护等诸多产业蓬勃发展&#xff0c;创造了巨大的感知产品增量需求。 在汽车领域&#xff0c;毫米波雷达传感器作为一种非接触…

Python 如何判断一个数组中的任意元素是否出现在另外一个数组中

需求 数组1&#xff1a;[双十一,工业机器人,智能物流,机器人概念,智慧停车,新能源汽车,智能制造] 数组2 &#xff1a;[专用设备,电力设备,化学制药,智能物流] 代码&#xff1a; def ExistsArray(sArray, dArray):result False;for item in sArray:if item in dArray:result …

微信小程序 地图撒点

1. 微信小程序 地图撒点 1.1 说明 首先使用微信小程序自带标签&#xff0c;并且设置好宽高让地图显示&#xff0c;用longitude和latitude表示中心点。   &#xff08;1&#xff09;show-location 显示带有方向的当前定位点,本项目不需要不添加。   &#xff08;2&#xff…

微软 Power Platform 零基础 Power Pages 网页搭建教程学习实践(一)

微软 Power Platform 零基础 Power Pages 网页搭建教程学习实践 Power Pages 网页搭建 微软 Power Platform 零基础 Power Pages 网页搭建教程学习实践1、Power Pages 介绍2、开始创建一个站点3、选择一个合适的模板4、编辑我们的模板5、面向专业开发人员的高级开发功能6、预览…

Python爬虫-新能源汽车销量榜

前言 本文是该专栏的第11篇,后面会持续分享python爬虫案例干货,记得关注。 本文以懂车平台的新能源汽车销量榜单为例,获取各车型的销量排行榜单数据。具体实现思路和详细逻辑,笔者将在正文结合完整代码进行详细介绍。 废话不多说,跟着笔者直接往下看正文详细内容。(附带…

GoWin FPGA--- startup2

clock Click Tools\IP Core Generator\rPLL, and open the configure file 原语 for Clock 双击选项&#xff0c;生产对应的代码&#xff0c;Copy到制定的地点。 右侧有对应的说明文件

document

原贴连接 1.在整个文档范围内查询元素节点 功能API返回值根据id值查询document.getElementById(“id值”)一个具体的元素节根据标签名查询document.getElementsByTagName(“标签名”)元素节点数组根据name属性值查询document.getElementsByName(“name值”)元素节点数组根据类…

element中el-table表头通过header-row-style设置样式

文章目录 一、知识点二、设置全部表头2.1、方式一2.2、方式二 三、设置某个表头四、最后 一、知识点 有些时候需要给element-ui表头设置不同样式&#xff0c;比如居中、背景色、字体大小等等&#xff0c;这时就可以用到本文要说的属性header-row-style。官网说明如下所示&…

如何删除mac苹果电脑上面的流氓软件?

在使用苹果电脑的过程中&#xff0c;有时候我们也会遇到一些不需要的软件。无论是因为不再需要&#xff0c;或者是为了释放磁盘空间&#xff0c;删除这些软件是很重要的。本文将为大家介绍怎样删除苹果电脑上的软件&#xff01; CleanMyMac X全新版下载如下: https://wm.make…