数据结构——双向链表dlist

server/2025/3/19 1:23:11/

前言:大家好😍,本文主要介绍了数据结构——双向链表dlist

一 双向链表定义

1. 双向链表的节点结构

 二 双向链表操作

 2.1 定义

2.2 初始化

2.3 插入

2.3.1 头插

2.3.2 尾插

2.3.3 按位置插

2.4 删除

2.4.1 头删

2.4.2 尾删

2.4.3 按位置删

2.5 其余操作

2.6 主函数测试


一 双向链表定义

双向链表(Doubly Linked List)是一种常见的线性数据结构,与单链表不同,双向链表的每个节点包含两个指针:一个指向前一个节点,一个指向后一个节点。这种结构使得双向链表支持从两个方向遍历,同时在插入和删除操作中更加灵活和高效。 

1. 双向链表的节点结构

双向链表的每个节点包含三个部分:

  1. 数据域:存储数据元素。

  2. 前驱指针(prev:指向当前节点的前一个节点。

  3. 后继指针(next:指向当前节点的后一个节点。

 二 双向链表操作

 2.1 定义

//定义了双向链表的结构体
typedef int ELEM_TYPE;struct DNode
{ELEM_TYPE data;  //数据域struct DNode* next; //下一个结点地址struct DNode* prior;//上一个
};typedef struct DNode DNode;
typedef struct DNode* PDNode;

2.2 初始化

void Init_Double_List(struct DNode* plist) //双向链表 第一种struct DNode*
{assert(plist != NULL);plist->next = NULL;plist->prior = NULL;
}

2.3 插入

2.3.1 头插

bool Insert_head(DNode* plist, ELEM_TYPE val)//二DNode*
{assert(plist != NULL);if (NULL == plist){exit(EXIT_FAILURE);}DNode* pnewnode = (DNode*)malloc(sizeof(DNode));if (NULL == pnewnode)exit(1);pnewnode->data = val;//插在辅助接点后面pnewnode->next = plist->next;pnewnode->prior = plist;if (!Is_Empty(plist)){pnewnode->next->prior = pnewnode;//这个也可以plist->next->prior = pnewnode;}plist->next = pnewnode;return true;}

2.3.2 尾插

bool Insert_tail(PDNode plist, ELEM_TYPE val)//三PDNode
{assert(NULL !=plist );if (NULL == plist){exit(EXIT_FAILURE);}//购买新节点DNode* pnewnode = (DNode*)malloc(sizeof(DNode));if (NULL == pnewnode)exit(1);pnewnode->data = val;//找到合适的待插入位置需要让一个临时指针p指向尾结点DNode* p = plist;while (p->next != NULL)p = p->next;//插入三行代码:只有三个指针域需要修改231	pnewnode->next = p->next;//nullpnewnode->prior = p;p->next = pnewnode;return true;}

2.3.3 按位置插

bool Insert_pos(DNode* plist, ELEM_TYPE val, int pos)
{assert(NULL != plist);if (NULL == plist){exit(EXIT_FAILURE);}//对pos合法性断言assert(pos >= 0 && pos <= Get_length(plist));//对pos判断 //pos=0 直接return头插函数//pos=length return尾插函数if (pos == 0){return Insert_head(plist, val);}else if(pos==Get_length(plist)){return Insert_tail(plist, val);}//剩下的pos都是合法且是中间位置,需要修改四个指针域//找到合适的插入位置让p指向待插入位置的上一个结点else{DNode* pnewnode = (DNode*)malloc(sizeof(DNode));if (NULL == pnewnode)exit(1);pnewnode->data = val;DNode* p = plist;while (p->next != NULL)p = p->next;//插入四行代码 因为有四个指针域要修改pnewnode->next = p->next;pnewnode->prior = p;pnewnode->next->prior = pnewnode;p->next = pnewnode;return true;}
}

2.4 删除

2.4.1 头删

bool Del_head(DNode* plist)
{//判空assert(NULL != plist);if (NULL == plist){exit(EXIT_FAILURE);}//判断链表是否为空if (Is_Empty(plist))return false;//申请俩个临时指针p和q,分别指向删除结点前驱和删除结点本身DNode* p = plist;//可以不要这行DNode* q = p->next;//区分情况 若是只有唯一一个有效结点 则只要需要修改一个指针域//              >1则修改俩个指针域if (Get_length(plist)>1){q->next->prior = p;}//跨越指向+释放p->next = q->next;free(q);q = NULL;return true;}

2.4.2 尾删

bool Del_tail(DNode* plist)
{assert(NULL != plist);if (NULL == plist){exit(EXIT_FAILURE);}//对双向链表判空if (Is_Empty(plist))return false;//辅助接点后有结点就可以尾删 //申请俩个临时指针p和q,分别指向删除结点前驱和删除结点本身DNode* p = plist;while (p->next->next != NULL)p = p->next;DNode* q = p->next;//跨越指向+释放p->next = q->next;free(q);q = NULL;return true;
}

2.4.3 按位置删

2.5 其余操作

//9.判空
bool Is_Empty(DNode* plist)
{return plist->next == NULL;
}//10获取有效值长度
int Get_length(DNode* plist)
{int count = 0;DNode* p = plist->next;for (; p != NULL;p=p->next){count++;}return count;
}//11.清空
void Clear(DNode* plist)
{Destroy1(plist);
}//12.销毁1(需要辅助节点参与进来)
void Destroy1(DNode* plist)
{//无限头删while (plist->next != NULL){Del_head(plist);}
}//13.销毁2(不需要辅助节点参与进来)相当于单链表的销毁
void Destroy2(DNode* plist)
{//不借助头结点//要用俩个指针pq去搭配 销毁所有结点//0.assert  head  //1.申请指针p,让其指向第一个有效结点DNode* p =plist->next;//p有可能为NULL, 有可能不空//2.申请指针q,先不给q赋值DNode* q = NULL; //因为p有可能是NULL,所以不能现在直接把p->next给到q//3.反复通过p和q打配合,去销毁后续节点while (p != NULL){q = p->next;free(p);p = q;}//4.节点全部销毁完毕,别忘了把辅助节点的指针域置空plist->next = NULL;//这一行代码可以帮助,下一次启用的时候,辅助节点不用初始化了
}//14.打印
void Show(DNode* plist)
{DNode* p = plist->next;for (; p != NULL;p=p->next){printf("%d", p->data);}printf("\n");
}

2.6 主函数测试

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

相关文章

.gitignore 文件用于 Git 应忽略的文件夹的格式

.gitignore 文件用于指定 Git 应忽略的文件或文件夹的匹配规则。以下是其语法规则和示例说明&#xff1a; 基本格式规则 每行一个规则&#xff1a;每个忽略规则单独占一行。 空行和注释&#xff1a; 空行会被忽略。 以 # 开头的行是注释&#xff08;除非用 \# 转义&#xff0…

【Vue3+Vite指南】全局引入SCSS文件后出现Undefined mixin?一招解决命名空间陷阱!

【Vue3Vite全局引入SCSS指南】解决Undefined mixin错误的完整方案 &#x1f4cc; 本文目录 前置准备&#xff1a;安装SCSS环境 问题现象与错误分析 根本原因&#xff1a;Sass模块化的命名空间 三大解决方案详解 方案1: 显式命名空间调用方案2: 全局暴露命名空间方案3: 主文件…

【Unity网络同步框架 - Nakama研究(四)】

文章目录 分析创建权威比赛控制台使用 【Unity网络同步框架 - Nakama研究(四)】 关于Nakama的源码问题&#xff0c;Nakama的源码官方是不建议修改的&#xff0c;不建议重构以添加新的功能&#xff0c;推荐使用嵌入式运行库&#xff0c;也就是使用lua,go和typescript进行扩展。 …

【项目管理git】git学习

ps&#xff1a;所有东西都是个人理解 文章目录 一、git是什么&#xff0c;它用来做什么&#xff1f;二、相关知识库2.1 简单的linux指令2.2 git配置指令2.3 git常见的指令2.3.1 Git的上传原理2.3.2 版本回退相关内容 2.4 设置远程地址&#xff0c;本地上传到github2.4.1 ssh相…

QT编程之HTTP服务端与客户端技术

一、HTTP 服务器实现方案 ‌QtWebApp 集成‌ 将QtWebApp源码的 httpserver 目录导入项目&#xff0c;并在 .pro 文件中添加 include ($$PWD/httpserver/httpserver.pri)‌。配置 WebApp.ini 文件定义服务参数&#xff08;IP、端口、线程池等&#xff09;&#xff0c;通过 HttpL…

Spring Cloud Stream - 构建高可靠消息驱动与事件溯源架构

一、引言 在分布式系统中&#xff0c;传统的 REST 调用模式往往导致耦合&#xff0c;难以满足高并发和异步解耦的需求。消息驱动架构&#xff08;EDA, Event-Driven Architecture&#xff09;通过异步通信、事件溯源等模式&#xff0c;提高了系统的扩展性与可观测性。 作为 S…

C++ primer plus 类和对象下

目录 前言 一 this指针 二 对象数组 三 类作用域 总结 前言 接着上一篇继续 一 this指针 我们可能看到这个this指针是不知道干什么的&#xff0c;但是我们可以通过一个问题来引入这个&#xff0c;就比如我们上一章的程序&#xff0c;我们知道是用来计算股票的&#xf…

前端(vue)学习笔记(CLASS 4):组件组成部分与通信

1、组件的三大组成部分&#xff08;结构/样式/逻辑&#xff09; 注意点&#xff1a; 1、结构只能有一个根元素 2、全局样式&#xff08;默认&#xff09;&#xff0c;影响所有组件&#xff1b;局部样式&#xff0c;scoped下样式&#xff0c;只作用于当前组件 3、el根实例独…