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

请添加图片描述

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

🍋双向链表

  • 🍌双向链表的定义与结构
  • 🍌双向链表增删查改(有头+双向+循环链表增删查改实现)
    • 🍍其它接口
    • 🍍创建返回链表的头结点
    • 🍍双向链表销毁
    • 🍍双向链表打印
    • 🍍双向链表尾插
    • 🍍双向链表尾删
    • 🍍双向链表头插
    • 🍍双向链表头删
    • 🍍双向链表查找
    • 🍍双向链表在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的头要指向curnode->next = cur;//cur的尾要指向pscur->tail = node;//ps的尾要指向curps->tail = cur;//cur的头要指向pscur->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.mzph.cn/news/213610.shtml

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

相关文章

程序启动时访问了未初始化的类指针引发内存访问违例导致程序崩溃的问题排查

目录 1、问题说明 2、使用Windbg动态调试去初步分析 3、使用Windbg详细分析 4、最后 VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycly/article/details/124272585C软件异常排查从入门…

20、XSS——XSS跨站脚本

文章目录 一、XSS漏洞概述1.1 XSS简介 二、XSS漏洞分类2.1 反射型XSS2.2 存储型XSS2.3 DOM型XSS 三、XSS payload构造以及变形3.1 XSS payload构造3.2 XSS payload 变形 一、XSS漏洞概述 1.1 XSS简介 XSS被称为跨站脚本攻击&#xff08;Cross-site scripting&#xff09;&…

k8s volumes and data

Overview 传统上&#xff0c;容器引擎(Container Engine)不提供比容器寿命更长的存储。由于容器被认为是瞬态(transient)的&#xff0c;这可能会导致数据丢失或复杂的外部存储选项。Kubernetes卷共享 Pod 生命周期&#xff0c;而不是其中的容器。如果容器终止&#xff0c;数据…

排序的简单理解(上)

1. 排序的概念及引用 1.1 排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作&#xff08;按照我们的需求能够有序的将数据信息排列起来&#xff09;。 稳定性&#xff1a;假…

TeeChart.NET 2023.11.17 Crack

.NET 的 TeeChart 图表控件提供了一个出色的通用组件套件&#xff0c;可满足无数的图表需求&#xff0c;也针对重要的垂直领域&#xff0c;例如金融、科学和统计领域。 数据可视化 数十种完全可定制的交互式图表类型、地图和仪表指示器&#xff0c;以及完整的功能集&#xff0c…

医疗设备智慧管理助力医院提质增效,阿基米德amp;健康界实践分享

近日&#xff0c;苏州阿基米德网络科技有限公司与医疗领域头部级媒体健康界&#xff0c;联合举办“数智为擎 提质增效——医学装备智慧管理创新发展论坛”的直播活动。 直播现场&#xff0c;来自上海交通大学医学院附属同仁医院、中华医学会航海医学分会、苏州阿基米德的专家们…

统信UOS_麒麟KYLINOS上使用命令行配置NTP服务器

原文链接&#xff1a;统信UOS/麒麟KYLINOS上使用命令行配置NTP hello&#xff0c;大家好啊&#xff0c;今天我要给大家介绍的是在统信UOS/麒麟KYLINOS操作系统上使用命令行配置NTP&#xff08;Network Time Protocol&#xff09;服务器的方法。在内网环境下&#xff0c;许多企业…

13、C++异常处理

13、c异常处理 抛出异常捕获异常未抛出异常时的流程抛出异常时的流程捕获异常匹配顺序异常说明异常处理构造函数中的异常析构函数中的异常标准库异常类 抛出异常 throw 异常对象可以抛出基本类型的对象&#xff0c;如:throw -1;throw "内存分配失败!";也可以抛出类类…

FreeSSL申请免费域名证书

本文详细讲解如何申请免费证书&#xff0c;需要先准备好域名&#xff0c;将服务器IP和域名绑定。 1、注册FreeSSL账号 网址&#xff1a; https://freessl.org/ 2、申请流程 登录后首页输入域名&#xff0c;然后点击Create certificate&#xff0c;跳转到证书申请页面。 或者…

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

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

QGIS 加载在线XYZ地图图层

QGIS 加载在线XYZ地图图层 定义并添加必应XYZ图层 Go to Layer > Add Layer > Add XYZ Layer…Click NewName as BingMaps(as you wish)URL as http://ecn.t3.tiles.virtualearth.net/tiles/a{q}.jpeg?g1click OkSelect XYZ Connections as Bing Maps(Which you creat…

PR自动剪辑视频工具AI智能剪辑插件AutoPod

推荐一款可以提高剪辑效率&#xff0c;节约时间成本的AI人工智能自动剪辑视频制作工具pr插件Autopod&#xff0c;辅助你更快地完成视频内容的编辑工作。 Autopod 插件是一款应用于 Adobe Premiere Pro 软件的插件&#xff0c;用于自动剪辑。该插件能够识别和处理视频和音频素材…

飞天使-linux操作的一些技巧与知识点4

文章目录 ansible配置文件的优先级尝试开始进行操作ansible常用模块ansible 的playbook示例安装phpplaybook中变量的引用 ansible yum install -y ansible 测试是否可用 ansible localhost -m ping /etc/ansible/ansible.cfg &#xff1a;主配置文件&#xff0c;配置 ansible…

大公司求我用Kotlin写个通用爬虫模板

bug虐我千百遍&#xff0c;我待他如初恋。每次深夜挑灯都是我与bug较量的时间。今天我要说的就是写一个爬虫模版&#xff0c;自动抓取百度图片的教程&#xff0c;这次使用Kotlin编写的爬虫程序在Scrapy框架下完成的&#xff0c;如有不足欢迎指正。 首先&#xff0c;使用Kotlin编…

angular form 组件、双向绑定;反应式表单

1.使用双向绑定&#xff0c;以及angular的表单提交功能 app.moudle中引入 双向绑定 [(ngModel)]"text" ​​​​​​​ 效果 提交表单 2.反应式表单 在app.module.ts中引入在组件中引入&#xff0c;并放在一个变量里 在初始化时实列化这个module 定义规则 在html…

Linux:环境变量

目录 1.基本变量 2.通过代码获取环境变量 2.1 main传参 2.2 全局变量environ 2.3 系统调用getenv() 3.在脚本文件中添加环境变量 4.环境变量通常是具有全局属性 1.基本变量 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数…

商用中央空调市场分析:预计2028年将达到628亿元

商用空调一直以来都没有一个相对比较明确的概念&#xff0c;一直以来被认为是制冷空调市场的一个细分子行业。现在比较一致的观点是&#xff0c;可以纳入商用空调范畴的产品可以包括户式中央空调产品、部分传统中央空调产品以及部分家用空调。商用空调已普遍采用直流变频领先技…

泡沫玻璃市场分析:预计2028年将达到14亿美元

泡沫玻璃最早是由美国匹兹堡康宁公司发明的&#xff0c;是由碎玻璃、发泡剂、改性添加剂和发泡促进剂等&#xff0c;经过细粉碎和均匀混合后&#xff0c;再经过高温熔化&#xff0c;发泡、退火而制成的无机非金属玻璃材料。它是由大量直径为1~2毫米的均匀气泡结构组成。其中吸声…

Linux 常用命令----mktemp 命令

文章目录 基本用法实例演示高级用法注意事项 mktemp 命令用于创建一个临时文件或目录&#xff0c;这在需要处理临时数据或进行安全性测试时非常有用。使用 mktemp 可以保证文件名的唯一性&#xff0c;避免因文件名冲突而导致的问题。 基本用法 创建临时文件: 命令 mktemp 默认…

Go语言基础知识学习(一)

Go基本数据类型 bool bool型值可以为true或者false,例子&#xff1a; var b bool true数值型 类型表示范围int8有符号8位整型-128 ~ 127int16有符号16位整型-32768 ~ 32767int32有符号32位整型-2147783648 ~ 2147483647int64有符号64位整型uint8无符号8位整型0 ~ 255uint16…