目录

1.简介

2.源码分享

3.链表模拟实现

3.1 动态申请一个节点

3.2初始化链表,创建头节点

3.3实现尾插

3.4 实现头插

3.5 实现头删

3.6 尾删

3.7打印链表

3.8实现查找

3.9 实现pos位置前插入数据

3.10 删除 pos 位置的节点

3.11 销毁链表


1.简介

带头双向循环链表:结构在链表中最为复杂,一般用来单独存放数据,实际中使用最多的链表结构。但是其只是结构复杂,使用起来其实比较简便。

2.源码分享

1. 带头双向循环链表源码  DList · 斯文/Date Stucture - 码云 - 开源中国 (gitee.com)

2. 不带头单向链表 博客(11条消息) 单链表详细解析,详细图解加代码实现,轻松拿捏。_杨斯文。的博客-CSDN博客

源码: Single linked list/Single linked list · 斯文/Date Stucture - 码云 - 开源中国 (gitee.com)

3.链表模拟实现

3.1 动态申请一个节点


typedef int DListdatatype;typedef struct DListNode
{DListdatatype data;struct DListNode* prev;struct DListNode* next;}DListNode;

由于我们需要做到双向循环,我们定义的结构体变量中需要两个指针,一个用来指向下一个,一个指向前一个。

// 创造节点
DListNode* BuyListNode(DListdatatype x)
{DListNode* Node = (DListNode*)malloc(sizeof(DListNode));Node->data = x;Node->next = NULL;Node->prev = NULL;return Node;
}

动态申请节点,返回申请的节点地址,将不确定的指针都先置空,避免出现野指针。

3.2初始化链表,创建头节点

// 初始化头结点
DListNode* ListInit()
{DListNode * head = BuyListNode(0);head->next = head;head->prev = head;
}

创造的头节点,并不使用数据,括号中的值可以随意输入。

3.3实现尾插

// 尾插
void PushBack(DListNode* p, DListdatatype x)
{assert(p);DListNode* newnode = BuyListNode(x);DListNode* tail = p -> prev;tail->next = newnode;newnode->prev = tail;newnode->next = p;p->prev = newnode;ListInsert(p, x);   利用pos前插入函数
}

其实函数的实现是比较简单的,记得处理好指针细节。

3.4 实现头插

// 头插
void ListPushFront(DListNode* p, DListdatatype x)
{assert(p);DListNode* newnode = BuyListNode(x);DListNode* cur = p->next;newnode->next = cur;newnode->prev = p;cur->prev = newnode;p->next = newnode;//ListInsert(p->next, x);
}

比较简单,不多做分析,处理好细节就可以了。

3.5 实现头删


// 头删
void ListPopFront(DListNode* p)
{assert(p);if (p->next == p){printf("链表已空\n");return;}else{DListNode* next = p->next;p->next = next->next;next->next->prev = p;free(next);}/*ListErase(p->next);*/// 需要多判断一步是否为空,不空再删
}

3.6 尾删


//  尾删void ListPopBack(DListNode* p)
{assert(p);if (p->next == p){printf("链表已空\n");return;}else{DListNode* tail = p->prev;tail->prev->next = p;p->prev = tail->prev;free(tail);}
/*  ListErase(p->prev); */ // 需要多判断一步是否为空,不空再删
}

3.7打印链表


// 打印
void ListPrint(DListNode* p)
{DListNode* cur = p->next;while (cur != p){printf("%d ", cur->data);cur = cur->next;}printf("\n");
}

由于是循环链表,打印链表和后续的查找函数的循环参数的判断条件就不可以是 NULL,我们取头节点后的第一个节点,遍历节点,循环时,等于头节点,即遍历了一遍链表,跳出循环。

3.8实现查找

//查找 x, 返回地址
DListNode* ListFind(DListNode* p, DListdatatype x)
{assert(p);DListNode* cur = p->next;while (cur != p){if (cur->data == x){printf("找到了\n");return cur;}cur = cur->next;}printf("没找到\n");return NULL;
}

3.9 实现pos位置前插入数据

// 在pos 位置前插入值 void ListInsert(DListNode* pos, DListdatatype x)
{DListNode* newnode = BuyListNode(x);DListNode* prev = pos->prev;newnode->next = pos;pos->prev = newnode;prev->next = newnode;newnode->prev = prev;}

注意pos后一个节点,注意替换顺序,避免丢失节点。

同时,我们可以使用这个函数来实现 ,头插,尾插

头插 : ListInsert(p->next, x);    在第一个数据节点前再插入新节点。

尾插:ListInsert(p, x);   利用pos前插入函数

尾插复杂一些

可以理解为,在头节点前插入一个节点,等于尾插。

3.10 删除 pos 位置的节点


//  删除pos 位置的 节点
void ListErase(DListNode* pos)
{assert(pos);pos->prev->next = pos->next;pos->next->prev = pos->prev;free(pos);
}

将pos 的前后节点链接到一起。

同理,可以使用这个函数实现头删,尾删

头删 :ListErase( p ->next) ;

尾删 : ListErase( p->prev);

3.11 销毁链表

// 销毁链表void ListDestroy(DListNode* p)
{assert(p);DListNode* cur = p->next;while (cur != p){DListNode* next = cur->next;free(cur);cur = next;}free(p);
}

需要注意循环链表的遍历条件 ,逐步销毁。

本篇博客到此结束,谢谢观看!

带头双向循环链表的模拟实现相关推荐

  1. 一文搞定带头双向循环链表

    什么是链表 链表的种类 最经典的两种链表 带头双向循环链表详细 什么是链表 在数据结构线性表里 除了顺序表 还有一种我们不得不说 他就是链表 链表的关键就是指针 创建出一块节点空间存储着 一边是val ...

  2. 数据结构与算法 | 带头双向循环链表

    上一节里实现的是最简单的链表,在实际中那种链表不会单独用来存储数据,更多是作为其他数据结构的子结构,如图的邻接表等.而比较常用的就是带头双向循环链表. 通过对比我们可以看出有三个不同,多了头节点,链表 ...

  3. 比特数据结构与算法(第二章收尾)带头双向循环链表的实现

    1.链表的分类 链表的分类 ① 单向或者双向 ② 带头或者不带头 ③ 循环或者非循环 常用的链表: 根据上面的分类我们可以细分出8种不同类型的链表,这么多链表我们一个个讲解这并没有意义.我们实际中最常 ...

  4. 【数据结构】链表:带头双向循环链表的增删查改

    本篇要分享的内容是带头双向链表,以下为本片目录 目录 一.链表的所有结构 二.带头双向链表 2.1尾部插入 2.2哨兵位的初始化 2.3头部插入 2.4 打印链表 2.5尾部删除 2.6头部删除 2. ...

  5. 数据结构-带头双向循环链表(增删查改详解)

    在上一篇博客中,详细介绍了单链表的增删查改,虽然单链表的结构简单,但是用起来却不是那么顺手.因此根据单链表的种种缺点,这篇博客所介绍的带头双向循环链表将会带来极大的优化. 上图就是带头双向循环链表的主 ...

  6. 初阶数据结构之带头+双向+循环链表增删查实现(三)

    文章目录 @[TOC](文章目录) 前言 一.带头双向循环链表的初始化 1.1带头双向循环链表的结构体定义 1.2初始化代码的实现 二.带头+双向+循环链表的增功能实现 2.1头插代码的实现 2.2尾 ...

  7. 数据结构:带头双向循环链表——增加、删除、查找、修改,详细解析

    读者可以先阅读这一篇:数据结构--单链表的增加.删除.查找.修改,详细解析_昵称就是昵称吧的博客-CSDN博客,可以更好的理解带头双向循环链表. 目录 一.带头双向循环链表的处理和介绍 1.带头双向循 ...

  8. 数据结构篇 --- 带头双向循环链表增删查改

    简述:有了前篇单链表的增删查改的基础 也是出于带头双向循环链表本身的优势  双链表的增删就变得格外简单.让我们一起来体验一下. 目录 带头双向循环链表图解: 带头双向循环链表基本结构: 带头双向循环链 ...

  9. 【数据结构】-关于带头双向循环链表的增删查改

    作者:低调 作者宣言:写好每一篇博客 文章目录 前言 一.带头双向循环链表的实现 1.1创建返回链表的头结点 1.2开辟一个新的结点 1.3双向链表的销毁 1.4双向链表的打印 1.5双向链表尾插 1 ...

最新文章

  1. Linux系统设置全局的默认网络代理
  2. python动态语言解释_python是动态语言吗
  3. 持续集成之 Jenkins 钉钉通知(八)
  4. Cannot find module 'express'
  5. 易语言自定义数据类型转c,一步一步跟我学易语言之自定义数据类型
  6. stm32f401 边沿捕获_STM32_capture 基于 设计的输入捕获实验,通过对边沿跳变的采集,得到外部接口 据。 SCM 单片机开发 261万源代码下载- www.pudn.com...
  7. python post上传大文件分片上传_基于七牛 用python实现分片上传 创建文件报错701...
  8. 通用汽车研发中心最新提出:3D车道线检测新方法
  9. 微信小程序开发:禁止输入表情的控制,验证方法,光标控制
  10. springboot之idea多模块
  11. esp8266 SOC方案经过半年沉淀之后再度重启二
  12. 如何快速播放CSF视频文件的办法
  13. oracle根据身份证号码计算年龄
  14. Kotlin中三元运算符
  15. 参考《机器学习实战》高清中文PDF+高清英文PDF+源代码
  16. html语言剖析十六 调色原理
  17. uni-app使用 getUserInfo 报错 fail can only be invoked by user TAP gesture 解决方法
  18. android10全面屏手势 操作图,丨系统设计丨ZUI 10加入更多全面屏手势
  19. 微信小程序绘制地图轨迹线路
  20. 新版傻妞升级之后 登录 查询无反应

热门文章

  1. android hid 音量,android Hid 实现注意事项
  2. GitChat · 架构 | 如何从零开始搭建高性能直播平台?
  3. CSU 1224: ACM小组的古怪象棋(BFS)
  4. linux查进程位置的命令
  5. linux 监听终端输入法,xinit 终端中文输入法
  6. ssh远程打开ubuntu的vino-server
  7. java编辑遗忘曲线代码_通过excel vba 实现艾宾浩斯遗忘曲线的复习提醒
  8. 使用百度地图Web服务API查询地点的经纬度信息
  9. vin端口是什么意思_振荡器基础1——为什么振荡器需要正反馈?什么是LC自激振荡器?...
  10. skywalking实战--agent异常日志监控