双向链表(数据结构与算法)

news2024/11/21 2:34:34

请添加图片描述

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿
🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟
🌟🌟 追风赶月莫停留 🌟🌟
🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀
🌟🌟 平芜尽处是春山🌟🌟
🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟
🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅

🍋双向链表

  • 🍌双向链表的定义与结构
  • 🍌双向链表增删查改(有头+双向+循环链表增删查改实现)
    • 🍍其它接口
    • 🍍创建返回链表的头结点
    • 🍍双向链表销毁
    • 🍍双向链表打印
    • 🍍双向链表尾插
    • 🍍双向链表尾删
    • 🍍双向链表头插
    • 🍍双向链表头删
    • 🍍双向链表查找
    • 🍍双向链表在pos的前面进行插入
    • 🍍双向链表删除pos位置的节点
  • 🍌双向链表整体代码的实现

🍌双向链表的定义与结构

在这里插入图片描述
双向链表:双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。(两个指针就是一个指向下一个数据,另一个指针指向上一个数据。如图中head头指针和tail尾指针)

在这里插入图片描述
在双向链表中还有一个特殊点,就是头指针,双向链表是带头的。在上次我们说的单链表中是不带头的,一旦涉及到头,我们就是先判断是不是为空,而在双向链表中就是不会涉及到这个问题了,不用再去一个一个的判断,就会省去很多的麻烦。

带头的双向链表嘴尾常用,所以我们这里就介绍带头的双向链表

🍌双向链表增删查改(有头+双向+循环链表增删查改实现)

🍍其它接口

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

typedef int LTdatetype;

typedef struct ListNode
{
	LTdatetype date;
	struct ListNode* next;
	struct ListNode* tail;
}ListNode;

定义一些接口

🍍创建返回链表的头结点

//创建返回链表的头结点
ListNode* Create(LTdatetype x)
{
	ListNode* cur =(ListNode*)malloc(sizeof(ListNode));
	if (cur == NULL)
	{
		perror("malloc  faild");
		exit(-1);
	}
	cur->next = NULL;
	cur->tail = NULL;
	cur->date = x;
	return cur;
}

ListNode* Inia()
{
	ListNode* node = Create(0);
	node->next = node;
	node->tail = node;

	return node;
}

Create函数就是创建一个节点。而Inia函数本来是进行初始化,而想要变成循环的链表,形参改变实参那就要用到二级指针,因为这里是双向链表,涉及头指针的时候不需要考虑二级指针,所以在这里就只有初始化需要用到头指针,所以我们就干脆用返回值,这样就不看起来违和了,当然用二级指针也没有什么问题,看自己习惯即可。

🍍双向链表销毁

// 双向链表销毁
void Destreoy(ListNode* ps)
{
	assert(ps);
	ListNode* cur = ps->next;
	while (cur != ps)
	{
		cur = cur->next;
		free(cur->tail);
	}
	free(ps);
}

🍍双向链表打印

// 双向链表打印
void Print(ListNode* ps)
{
	assert(ps);
	ListNode* cur = ps->next;
	while (cur != ps)
	{
		printf("%d<=>", cur->date);
		cur = cur->next;
	}
}

在这里插入图片描述

在这里打印,我们就不能使用和单链表打印的方法了,因为我们这里是循环链表,并且我们的ps里面没有存有数据,所以我们要从ps的下个数据开始,也就是图中cur的位置,然后在cur到ps的时候跳出循环就可以了。

🍍双向链表尾插

// 双向链表尾插
void LTpushbake(ListNode* ps, LTdatetype x)
{
	assert(ps);
	ListNode* cur = Create(x);
	ListNode *node = ps->tail ;
	
	//ps的头要指向cur
	node->next = cur;
	//cur的尾要指向ps
	cur->tail = node;

	//ps的尾要指向cur
	ps->tail = cur;
	//cur的头要指向ps
	cur->next = ps;
}

在这里插入图片描述

之所以要这样的指向,是因为这是一个循环的双向链表

🍍双向链表尾删

// 双向链表尾删
void LTpopbake(ListNode* ps)
{
	assert(ps);
	assert(ps->next != ps);
	ListNode* cur = ps->tail;
	ListNode* curtail = cur->tail;

	free(cur);
	cur->next = cur->tail = NULL;

	curtail->next = ps;
	ps->tail = curtail;

}

在这里插入图片描述
在这里因为这是循环链表所以不用遍历去找尾结点,当然用遍历也是可以的

🍍双向链表头插

// 双向链表头插
void LTpushfront(ListNode* ps, LTdatetype x)
{
	assert(ps);
	ListNode* node = Create(x);

	ListNode* cur = ps->next;

	ps->next = node;
	node->tail = ps;

	node->next = cur;
	cur->tail = node;

}

在这里插入图片描述
带头的链表中,头插是最方便的,不用像不带头的单链表中一个一个去判断,大大的节省了我们的时间

🍍双向链表头删

// 双向链表头删
void LTpopfront(ListNode* ps)
{
	assert(ps);
	assert(ps->next != ps);
	ListNode* node = ps->next;
	ListNode* node_next = node->next;

	free(node);

	ps->next = node_next;
	node_next->tail = ps;
}

在这里插入图片描述
带头的链表中,头删也很方便了。

🍍双向链表查找

// 双向链表查找
ListNode * LTfind(ListNode* ps, LTdatetype x)
{
	assert(ps);
	ListNode* cur = ps->next;
	while (cur != ps)
	{
		if (cur->date == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

关于这个查找还是要注意下,因为我们这里是循环链表,所以要注意记得要设置跳出循环的条件

🍍双向链表在pos的前面进行插入

// 双向链表在pos的前面进行插入
void LTinsert(ListNode *pos, LTdatetype x)
{
	assert(pos);
	ListNode* node = Create(x);
	ListNode* pos_tail = pos->tail;

	pos_tail->next = node;
	node->tail = pos_tail;

	node->next = pos;
	pos->tail = node;

}

在这里插入图片描述
在pos前插入和头插,尾插差不多的意思

🍍双向链表删除pos位置的节点

// 双向链表删除pos位置的节点
void LTdelete(ListNode* pos)
{
	assert(pos);
	ListNode* pos_tail = pos->tail;
	ListNode* pos_next = pos->next;

	free(pos);

	pos_tail->next = pos_next;
	pos_next->tail = pos_tail;
}

在这里插入图片描述

删除pos位置,也差不多和前面意思都差不多

🍌双向链表整体代码的实现

#include<stdio.h>
#include<assert.h>
#include<stdlib.h>

typedef int LTdatetype;


//创建返回链表的头结点
typedef struct ListNode
{
	LTdatetype date;
	struct ListNode* next;
	struct ListNode* tail;
}ListNode;

ListNode* Create(LTdatetype x)
{
	ListNode* cur = (ListNode*)malloc(sizeof(ListNode));
	if (cur == NULL)
	{
		perror("malloc  faild");
		exit(-1);
	}
	cur->next = NULL;
	cur->tail = NULL;
	cur->date = x;
	return cur;
}

ListNode* Inia()
{
	ListNode* node = Create(0);
	node->next = node;
	node->tail = node;

	return node;
}


// 双向链表销毁
void Destreoy(ListNode* ps)
{
	assert(ps);
	ListNode* cur = ps->next;
	while (cur != ps)
	{
		cur = cur->next;
		free(cur->tail);
	}
	free(ps);
}

// 双向链表打印
void LTprint(ListNode* ps)
{
	assert(ps);
	ListNode* cur = ps->next;
	printf("ps<=>");
	while (cur != ps)
	{
		printf("%d<=>", cur->date);
		cur = cur->next;
	}
	printf("\n");
}

// 双向链表尾插
void LTpushbake(ListNode* ps, LTdatetype x)
{
	assert(ps);
	ListNode* cur = Create(x);
	ListNode* node = ps->tail;

	node->next = cur;
	cur->tail = node;

	ps->tail = cur;
	cur->next = ps;
}

// 双向链表尾删
void LTpopbake(ListNode* ps)
{
	assert(ps);
	assert(ps->next != ps);
	ListNode* cur = ps->tail;
	ListNode* curtail = cur->tail;

	free(cur);

	curtail->next = ps;
	ps->tail = curtail;

}

// 双向链表头插
void LTpushfront(ListNode* ps, LTdatetype x)
{
	assert(ps);
	ListNode* node = Create(x);

	ListNode* cur = ps->next;

	ps->next = node;
	node->tail = ps;

	node->next = cur;
	cur->tail = node;

}


// 双向链表头删
void LTpopfront(ListNode* ps)
{
	assert(ps);
	assert(ps->next != ps);
	ListNode* node = ps->next;
	ListNode* node_next = node->next;

	free(node);

	ps->next = node_next;
	node_next->tail = ps;
}

// 双向链表查找
ListNode * LTfind(ListNode* ps, LTdatetype x)
{
	assert(ps);
	ListNode* cur = ps->next;
	while (cur != ps)
	{
		if (cur->date == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}


// 双向链表在pos的前面进行插入
void LTinsert(ListNode *pos, LTdatetype x)
{
	assert(pos);
	ListNode* node = Create(x);
	ListNode* pos_tail = pos->tail;

	pos_tail->next = node;
	node->tail = pos_tail;

	node->next = pos;
	pos->tail = node;

}

// 双向链表删除pos位置的节点
void LTdelete(ListNode* pos)
{
	assert(pos);
	ListNode* pos_tail = pos->tail;
	ListNode* pos_next = pos->next;

	free(pos);

	pos_tail->next = pos_next;
	pos_next->tail = pos_tail;
}


void test1()//测试
{
	ListNode* ps = Inia();
	LTpushbake(ps, 1);//尾插
	LTpushbake(ps, 2);//尾插
	LTpushbake(ps, 3);//尾插
	LTpushbake(ps, 4);//尾插
	LTprint(ps);//打印

	LTpopbake(ps);//尾删
	LTprint(ps);//打印

	LTpushfront(ps, 10);//头插
	LTpushfront(ps, 11);//头插
	LTpushfront(ps, 12);//头插
	LTpushfront(ps, 13);//头插
	LTprint(ps);//打印

	LTpopfront(ps);//头删
	LTprint(ps);//打印

	ListNode *pos = LTfind(ps, 11);//双向链表查找
	if (pos == NULL)
	{
		printf("没找到\n");
	}
	else
	{
		printf("找到了,为:%d\n", pos->date);
	}

	LTinsert(pos, 100);// 双向链表在pos的前面进行插入
	LTprint(ps);//打印

	LTdelete(pos);//双向链表删除pos位置的节点
	LTprint(ps);//打印

	Destreoy(ps);//双向链表销毁
}

int main()
{
	test1();//测试
	return 0;
}

带头的双向链表实现起来还是非常简单的,大家如果对于文章中的某一个点有问题,欢迎私聊我。

请添加图片描述

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

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

相关文章

基于Java的商城网站系统设计与实现(6000字论文范例)

基于Java的商城网站系统设计与实现 姓 名&#xff1a; 刘德华 学 号&#xff1a; 指导教师&#xff1a; 2023年4月 摘要 随着我国经济活力的不断提升和互联网的快速发展&#xff0c;信息的重要性正在…

SpringIOC之ConditionEvaluator

博主介绍:✌全网粉丝5W+,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验✌ 博主作品:《Java项目案例》主要基于SpringBoot+MyBatis/MyBatis-plus+…

如何使用cpolar+Inis在Ubuntu系统快速搭建本地博客网站公网可访问

文章目录 前言1. Inis博客网站搭建1.1. Inis博客网站下载和安装1.2 Inis博客网站测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 3. 公网访问测试总…

安装Nacos2.2.3集群

目录 一、传统方式安装 二、Docker安装 一、传统方式安装 1、配置jdk环境 vi /etc/profile JAVA_HOME/usr/local/java JRE_HOME/usr/local/java/jre CLASSPATH.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib PATH$JAVA_HOME/bin:$PATH export PATH JAVA_…

统筹高级前端,系统进阶精选案例实战,高效奠定前端基石

在当今的软件开发中&#xff0c;前端技术的重要性日益突出。为了应对不断变化的市场需求和用户期望&#xff0c;前端开发人员需要不断进阶&#xff0c;并掌握高级技术和系统化的实战经验。本文将介绍一些高级前端开发的精选案例&#xff0c;帮助开发者高效地奠定前端基石&#…

WRF--修改geo_em.d01.nc中的变量,保持其他信息不变

WRF–修改geo_em.d01.nc中的变量&#xff0c;保持其他信息不变 首先呢&#xff0c;找到编译WRF过程中自带的读取nc的一个fortran函数&#xff1a;read_wrf_nc.f90 可以使用Linux命令&#xff1a; find / -name read_wrf_nc.f90 找到之后&#xff0c;修改这个文件&#xff0c…

ke14--10章-1数据库JDBC介绍

注册数据库(两种方式),获取连接,通过Connection对象获取Statement对象,使用Statement执行SQL语句。操作ResultSet结果集 ,回收数据库资源. 需要语句: 1Class.forName("DriverName");2Connection conn DriverManager.getConnection(String url, String user, String…

通过异步序列化提高图表性能 Diagramming for WPF

通过异步序列化提高图表性能 2023 年 12 月 6 日 MindFusion.Diagramming for WPF 4.0.0 添加了异步加载和保存文件的功能&#xff0c;从而提高了响应能力。 MindFusion.Diagramming for WPF 提供了一个全面的工具集&#xff0c;用于创建各种图表&#xff0c;包括组织结构图、图…

华为数通---配置本地端口镜像示例(1:1)

镜像概念 定义 镜像是指将指定源的报文复制一份到目的端口。指定源被称为镜像源&#xff0c;目的端口被称为观察端口&#xff0c;复制的报文被称为镜像报文。 镜像可以在不影响设备对原始报文正常处理的情况下&#xff0c;将其复制一份&#xff0c;并通过观察端口发送给监控…

IntelliJ IDEA无公网远程连接Windows本地Mysql数据库提高开发效率

&#x1f525;博客主页&#xff1a; 小羊失眠啦. &#x1f3a5;系列专栏&#xff1a;《C语言》 《数据结构》 《Linux》《Cpolar》 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;…

每日一练【查找总价格为目标值的两个商品】

一、题目描述 题目链接 购物车内的商品价格按照升序记录于数组 price。请在购物车中找到两个商品的价格总和刚好是 target。若存在多种情况&#xff0c;返回任一结果即可。 示例 1&#xff1a; 输入&#xff1a;price [3, 9, 12, 15], target 18 输出&#xff1a;[3,15] …

Pytorch深度强化学习1-6:详解时序差分强化学习(SARSA、Q-Learning算法)

目录 0 专栏介绍1 时序差分强化学习2 策略评估原理3 策略改进原理3.1 SARSA算法3.2 Q-Learning算法 0 专栏介绍 本专栏重点介绍强化学习技术的数学原理&#xff0c;并且采用Pytorch框架对常见的强化学习算法、案例进行实现&#xff0c;帮助读者理解并快速上手开发。同时&#…

摄像机镜头,家庭监控云台等安防监控系统镜头选型分析,低噪声,低振动,多通道

安防镜头步进驱动选用型号 GC6107 C6109 GC6209 GC6119 GC6129 GC6139 GC6208 GC6150 GC6151 GC6152 GC6125 GC6236采用5V的镜头驱动 。其中GC6107 C6109 GC6209 GC6119 GC6129 GC6139 GC6208关键特性两通道&#xff0c;256细分&#xff0c;低噪&#xff0c;内部和外部时钟…

【算法系列篇】递归、搜索和回溯(二)

文章目录 前言1. 两两交换链表中的节点1.1 题目要求1.2 做题思路1.3 代码实现 2. Pow(X,N)2.1 题目要求2.2 做题思路2.3 代码实现 3. 计算布尔二叉树的值3.1 题目要求3.2 做题思路3.3 代码实现 4. 求根节点到叶结点数字之和4.1 题目要求4.2 做题思路4.3 代码实现 前言 前面为大…

解锁数据安全秘诀:医药企业选择上海迅软DSE,防范泄密威胁!

随着数字化和信息化程度的提高&#xff0c;医药企业存储了大量的患者医疗记录、药品研发数据、临床试验数据以及财务信息。但由于医药行业的特殊性和敏感性&#xff0c;其数据的变现价值非常高&#xff0c;在各种利益的非法驱动下&#xff0c;医药行业早已成为数据泄露的重灾区…

想知道修改图片dpi会影响清晰度吗?点击这里找答案

很多人都对图片dpi分辨率有不少疑问&#xff0c;比如dpi对图片清晰的影响&#xff0c;还有哪些地方需要修改图片dpi&#xff1f;其实dpi是指每英寸墨点的数量。对同一张图像来说,一般使用300dpi比使用72dpi打印出来的效果要清晰很多 &#xff0c;一般只有在打印照片或者上传证件…

Windows系统Java开发环境安装

总结一下Java软件开发工程师常见的环境的安装&#xff0c;仅限Windows环境。 以下下载链接均来自官网&#xff0c;网络条件自己克服。 目录 1. JDKJDK Oracle 官网下载地址配置系统环境变量 2. Mavenapache maven 官网地址本地仓库和中央仓库配置配置系统环境变量 3. GitGit 官…

java学习part42反射

187-反射机制-反射的理解与使用举例_哔哩哔哩_bilibili

Python实现获取b站视频的弹幕内容

前言 本文是该专栏的第39篇,后面会持续分享python的各种干货知识,值得关注。 在本专栏之前,有详细介绍使用python增加b站视频的播放量方法,感兴趣的同学可往前翻阅《Python-增加b站视频播放量》。而本文,笔者再来单独的详细介绍,通过python来获取b站视频的弹幕内容。如下…

应用程序清理和卸载缓存清理软件:App Cleaner Uninstaller Pro Mac中文

App Cleaner & Uninstaller Pro是一款专为Mac电脑设计的应用程序清理和卸载工具。它帮助用户彻底删除不需要的应用程序、插件和残留文件&#xff0c;从而有效释放磁盘空间并提高系统性能。其强大的搜索功能和批量卸载特性使得管理应用程序变得轻而易举。同时&#xff0c;用…