数据结构:双向链表

一.双向链表的结构

最常用的链表就是单链表和双向链表。我们首先要知道,链表有八种分类。单链表是不带头单向不循环链表。而此篇博客要讲的是带头双向循环链表。

结构如下:

注意:带头链表里的头节点,实际为“哨兵位”,哨兵位节点不存储任何有效元素,只是站在这里“放哨的” 。它存在的意义就是遍历循环链表避免死循环。

我们所说的双向链表为空,跟单链表不同,双向链表就是只存在哨兵位。双向链表的实现就比单链表简单的多了。

二.双向链表的实现

1.申请一个新节点和初始化

//创建一个新节点
LTNode* LTBuyNode(LTDataType x)
{LTNode* node = (LTNode*)malloc(sizeof(LTNode));//动态申请空间if (node == NULL){perror("node");exit(1);}node->next = node;node->prev = node;//把新节点的next指针和prev指针都指向自己node->data = x;return node;//返回我们的新节点
}
//初始化
void LTInit(LTNode** pphead)
{//给双向链表创建一个哨兵位*pphead = LTBuyNode(-1);//初始化时我们需要改变首节点,用二级指针传参
}

注意在创建新节点的时候我们一定要把next指针和prev都指向自己。初始化其实就是给我们创建一个哨兵位。

其实初始化不用二级指针也可以做到初始话:

//不用二级指针的初始化
LTNode* LTInit(LTNode* phead)
{phead = LTBuyNode(-1);return phead;
}

返回指针就行了。

2.尾插

//尾插
void LTPushBack(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);//创建一个新节点newnode->prev = phead->prev;newnode->next = phead;//先把newnode的指向指针都给改了phead->prev->next = newnode;phead->prev = newnode;//这一行不能与上一行交换位置
}

为了方便查看我们写的代码是否有错误,我们可以打印出来:

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

这个是在后面的测试过程来用的。

3.头插

//头插
void LTPushFront(LTNode* phead, LTDataType x)
{assert(phead);LTNode* newnode = LTBuyNode(x);newnode->prev = phead;newnode->next = phead->next;//先改变newnode节点指针的指向phead->next->prev = newnode;phead->next = newnode;//同样这两个的位置也不可以调换
}

4.尾删

尾删就更简单了:

//尾删
void LTPopBack(LTNode* phead)
{assert(phead&&phead->next!=NULL);//链表必须不能为NULL,且必须有效LTNode* del = phead->prev;//把尾节点存起来del->prev->next = phead;phead->prev = del->prev;free(del);del = NULL;//释放后置为NULL,这是习惯
}

5.头删

头删的时候一定要注意,我们删的可不是哨兵位,是有效位的头。

//头删
void LTPopFront(LTNode* phead)
{assert(phead && phead->next != NULL);LTNode* del = phead->next;del->next->prev = phead;phead->next = del->next;//这两行代码可以互换,因为我们已经提前把phead->next的值存起来了free(del);del = NULL;
}

6.指定位置之后插入

在指定位置插入,我们可以先写一个函数来找到指定位置:

LTNode* LTFind(LTNode* phead, LTDataType x)
{LTNode* pcur = phead->next;while (pcur != phead)//遍历双向链表{if (pcur->data == x){return pcur;}pcur = pcur->next;}//没有找到return NULL;
}

然后执行插入:

//在pos位置之后插入数据
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;
}

7.删除指定节点

//删除pos节点
void LTErase(LTNode* pos)
{//pos理论上来说不能为phead,但是没有参数phead,无法增加校验assert(pos);pos->next->prev = pos->prev;pos->prev->next = pos->next;free(pos);pos = NULL;
}

8.销毁链表

void LTDesTroy(LTNode* phead)
{assert(phead);LTNode* pcur = phead->next;while (pcur != phead){LTNode* next = pcur->next;free(pcur);pcur = next;}//此时pcur指向phead,而phead还没有被销毁free(phead);phead = NULL;
}

三.双向链表功能实现的测试

void text1()
{//初始化LTNode* plist = LTInit();//尾插LTPushBack(plist, 1);LTPushBack(plist, 2);LTPushBack(plist, 3);//打印LTPrint(plist);//头插LTPushFront(plist, 100);LTPushFront(plist, 200);LTPushFront(plist, 300);LTPrint(plist);//尾删LTPopBack(plist);LTPrint(plist);//头删LTPopFront(plist);LTPrint(plist);//查找LTNode* find = LTFind(plist, 1);//在指定位置之后插入数据LTInsert(find, 66);LTPrint(plist);//删除指定位置的数据LTErase(find);find = NULL;LTPrint(plist);//销毁链表LTDesTroy(find);plist=NULL;
}
int main()
{text1();return 0;
}

为了保证接口的一致性,即使是LTErase和LTDesTory这些理论上需要传递二级指针的函数,我们也给它传递了一级指针。但是我们一定要注意 LTDesTory和LTErase当我们在函数内部把节点给释放掉之后,在函数的内部我们把释放掉的指针给置为了NULL,但是在出了函数的时候,我们是实参并没有置为NULL,所以我们需要多加一步对实参置为NULL,这样代码才完整。

关于双向链表是比单向链表要简单的多的。感谢大家的观看,如有错误,请多多指出。

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

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

相关文章

【python】python饮料销售数据分析可视化(源码+数据集)【独一无二】

👉博__主👈:米码收割机 👉技__能👈:C/Python语言 👉公众号👈:测试开发自动化【获取源码商业合作】 👉荣__誉👈:阿里云博客专家博主、5…

机器人瓶胚检测工作站(H3U脉冲轴控制)

1、变量定义 2、程序监控1 2、 程序监控2 3、程序监控3 机器人输送料和机构的动作安全尤为重要,下面我们讨论下安全联锁控制逻辑 4、相机拍照触发信号 5、相机拍照触发时序

回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测

回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测 目录 回归预测 | MATLAB实现BO-GRNN贝叶斯优化广义回归神经网络多输入单输出预测预测效果基本介绍程序设计参考资料预测效果 基本介绍

【SpringBoot】获取参数

获取参数 传递单个参数传递多个参数传递对象后端参数重命名传递数组传递 json 数据获取 URL 中参数上传文件获取 cookie 和 session获取cookie获取session 传递单个参数 RequestMapping("/user") RestController public class UserController {// 传递单个参数Reque…

简单好用的SaaS知识库工具都在这了,看完赶紧收藏!

在信息飞速发展的今天,企业如何有效地管理海量的信息和知识成为了提高工作效率的关键。SaaS知识库工具正成为企业寻求的解决方案,它们不仅能够帮助团队组织文档,而且优化知识分享流程。现在就让我们来看看市场上几款简单又好用的SaaS知识库工…

华为云配置安全组策略开放端口

🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C 🔥座右铭:“不要等到什么都没有了,才下…

C语言 | 内存函数memcpy,memmove,memset,memcmp

目录&#xff1a; 1. memcpy使用和模拟实现 2. memmove使用和模拟实现 3. memset函数的使用 4. memcmp函数的使用 头文件&#xff1a;<string.h> 1. memcpy使用和模拟实现 void * memcpy ( void * destination, const void * source, size_t num ); • 从source的…

【CPA考试】2024注册会计师报名照片尺寸要求解读及手机拍照方法

随着2024年注册会计师考试的临近&#xff0c;众多会计专业人士和学生都开始准备报名参加这一行业的重要考试&#xff0c;报名时间为4月8日至4月30日。报名过程中&#xff0c;一张符合要求的证件照是必不可少的。本文将为您详细解读2024年注册会计师考试报名照片的尺寸要求&…

Git以及Gitlab的快速使用文档

优质博文&#xff1a;IT-BLOG-CN 安装git 【1】Windows为例&#xff0c;去百度下载安装包。或者去官网下载。安装过秳返里略过&#xff0c;一直下一步即可。丌要忉记设置环境发量。 【2】打开cmd&#xff0c;输入git –version正确输出版本后则git安装成功。 配置ssh Git和s…

C++ 之 【类与对象】 从入门到精通一条龙服务 进阶篇(类的6个默认成员函数,构造,析构。。。)

以后把闹钟换成唢呐&#xff0c;醒了就起床&#xff0c;不醒就上天堂 一、类的6个默认成员函数 二、构造函数 1.概念 2.特性 三、析构函数 1.概念 2.特性 四、拷贝构造函数 1.概念 2.特征 五、赋值运算符重载 1.运算符重载 2.赋值运算符重载 3.前置和后置重载 六…

rancher踩坑日志:prometheus访问kubelet 10250端口提示鉴权失败

该原因是因为kubectl禁止了非授权用户访问10250端口来获取node的数据。 解决思路&#xff1a; 添加prometheus访问kubelet时带上证书进行验证匹配 --> 由于我的prometheus是rancher安装的&#xff0c;不知道要怎么修改所以研究了一会没研究明白就放弃了。设置prometheus访问…

关于Ribbon在SpringCloudAlibaba2021.1版本中,找不到服务实例

关于Ribbon在SpringCloudAlibaba2021.1版本中&#xff0c;找不到服务实例 放个妹子 SpringCloudAlibaba在2021.1版本中,spring-cloud-starter-alibaba-nacos-discovery默认已经移除了ribbon模块 手动加上spring-cloud-starter-netflix-ribbon依赖后&#xff0c;项目能正常启动…

如何将CSDN的文章以PDF文件形式保存到本地

1.F12 打开开发者工具窗口 2.console下输入命令 (function(){$("#side").remove();$("#comment_title, #comment_list, #comment_bar, #comment_form, .announce, #ad_cen, #ad_bot").remove();$(".nav_top_2011, #header, #navigator").remove…

蓝桥杯 前一晚总结 模板 新手版

《准备实足&#xff0c;冲冲冲 省一》https://www.yuque.com/lenyan-svokd/hi7hp2/hfka297matrtsxy2?singleDoc# 《准备实足&#xff0c;冲冲冲 省一》 #include<bits/stdc.h> // 包含标准库头文件using namespace std; using ll long long; // 定义 long long 数据类…

iOS开发如何更改xcode中的Apple ID

在Xcode中更改Apple ID是一项常见的任务&#xff0c;尤其是当你需要切换到另一个开发者账号或者团队时。下面是一个简单的步骤指南&#xff0c;帮助你更改Xcode中的Apple ID&#xff1a; 步骤一&#xff1a;退出当前的Apple ID 1.打开Xcode应用程序。 2.在菜单栏中&#xff0c;…

Spring Validation解决后端表单校验

NotNull&#xff1a;从前台传递过来的参数不能为null,如果为空&#xff0c;会在控制台日志中把message打印出来 Range&#xff1a;范围&#xff0c;最大多少&#xff0c;最小多少 Patten&#xff0c;标注的字段值必须符合定义的正则表达式&#xff08;按照业务规则&#xff0…

【计算机毕业设计】人事管理系统——后附源码

&#x1f389;**欢迎来到我的技术世界&#xff01;**&#x1f389; &#x1f4d8; 博主小档案&#xff1a; 一名来自世界500强的资深程序媛&#xff0c;毕业于国内知名985高校。 &#x1f527; 技术专长&#xff1a; 在深度学习任务中展现出卓越的能力&#xff0c;包括但不限于…

如何使用 ArcGIS Pro 制作热力图

热力图是一种用颜色表示数据密度的地图&#xff0c;通常用来显示空间分布数据的热度或密度&#xff0c;我们可以通过 ArcGIS Pro 来制作热力图&#xff0c;这里为大家介绍一下制作的方法&#xff0c;希望能对你有所帮助。 数据来源 教程所使用的数据是从水经微图中下载的POI数…

Adobe——一些细节坑

一、容易踩坑一 默认是进行了以A4输出&#xff0c;采用比例缩放的&#xff0c;建议勾选 按照PDF页面大小选择纸张来源。

爬虫逆向非对称加密和对称加密案例

注意&#xff01;&#xff01;&#xff01;&#xff01;某XX网站逆向实例仅作为学习案例&#xff0c;禁止其他个人以及团体做谋利用途&#xff01;&#xff01;&#xff01; 案例--aHR0cHM6Ly9jcmVkaXQuaGxqLmdvdi5jbi94eWdzL3l6d2ZzeHF5bWQv 第一步&#xff1a;分析页面、请求…