数据结构——双向链表dlist

ops/2025/3/19 6:25:04/

前言:大家好😍,本文主要介绍了数据结构——双向链表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 主函数测试


http://www.ppmy.cn/ops/166963.html

相关文章

【PyTorch】.pt文件

.pt文件是 PyTorch 中用于保存张量&#xff08;torch.Tensor&#xff09;或模型&#xff08;torch.nn.Module&#xff09;的二进制文件格式。它使用 PyTorch 的序列化机制来保存数据&#xff0c;能够高效地存储和加载张量或模型的状态。 .pt 文件中存储的内容 1. 张量&#x…

pnpm config set ignore-workspace-root-check true

异常 ERR_PNPM_ADDING_TO_ROOT  Running this command will add the dependency to the workspace root, which might not be what you want - if you really meant it, make it explicit by running this command again with the -w flag (or --workspace-root). If you don…

【后端】【django】Django DRF `@action` 详解:自定义 ViewSet 方法

Django DRF action 详解&#xff1a;自定义 ViewSet 方法 在 Django REST Framework&#xff08;DRF&#xff09;中&#xff0c;action 装饰器用于为 ViewSet 添加自定义的 API 端点。相比于 update、create 等默认方法&#xff0c;action 允许我们定义 更加清晰、语义化 的 A…

springboot基于session实现登录

文章目录 1.理解session2.理解ThreadLocal2.1 理解多线程2.2 理解lambda表达式2.3 ThreadLocal 3.基于session登录流程图4.具体登录的代码实现4.1短信发送功能4.2 短信验证码登录注册功能4.登录校验功能4.1 配置登录拦截器LoginInterceptor4.1.1 ThrealLocal类实现 4.2登录拦截…

EditRocket for Mac v5.0.2 文本编辑器 支持M、Intel芯片

应用介绍 EditRocket 是一款强大的跨平台文本编辑器&#xff0c;专为程序员、开发者和技术人员设计&#xff0c;提供了丰富的编程支持和多种开发工具。它支持各种编程语言&#xff0c;具备高效的代码编辑、调试、和文本处理功能&#xff0c;旨在提升编程效率和开发体验。 主要…

c语言数据结构——单向不带头不循环链表的实现

文章目录 单向不带头不循环链表链表与顺序表的区别多文件管理链表的定义结构获得链表节点个数链表增加元素链表的尾插及创建节点函数链表的头插任意位置节点后插入 判断链表是否为空链表删除元素链表的尾删链表的头删任意位置删除 链表查找元素链表修改元素单向链表的遍历链表销…

reactive数据修改无效

环境 vue&#xff1a;3.2.13 element-plus: 2.9.6 typescript&#xff1a;4.5.5 问题 表格列表页面&#xff0c;页面中有新增和修改操作&#xff0c;新增和修改共用一个弹窗&#xff0c;弹窗中表单绑定的数据修改无效。复现步骤是先点击表格中的修改&#xff0c;然后点击新…

jasypt-spring-boot-starter项目如何使用jasypt加密密码

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor; import org.jasypt.iv.RandomIvGenerator; import org.jasypt.salt.RandomSaltGenerator;/*** 加密密码的工具** author xxx* since 2025-03-17*/ public class JasyptTest {public static void main(String[] a…