1. 什么是链表
  2. 链表的种类
  3. 最经典的两种链表
  4. 带头双向循环链表详细
  • 什么是链表

在数据结构线性表里 除了顺序表 还有一种我们不得不说 他就是链表

链表的关键就是指针 创建出一块节点空间存储着 一边是val数值 另一边是next下一个节点空间的地址 每个节点空间由next这种指针串联在一起 这就是链表的基础模型

由链表带来的结构优势 弥补了顺序表的缺点  链表不需要按需申请释放不用挪动数据就可以增添数据 

  • 链表的种类

链表有这几种特性 分别是

1. 带头               不带头

2.单                       双

3.循环                不循环

两两组合 链表则共有八种类型       这八种链表各有千秋 由实际情况 而选择哪种链表

  • 最经典的两种链表

在这八种链表里 我们最常见最常用的就是 单链表 带头双向循环链表 这两种

  • 带头双向循环链表详细

而本文的重点就是 解析带头双向循环链表 别看它名字又长又复杂 其实这种链表 实现起来十分简单 在模拟实现时 能很清楚的感觉到 它带来的结构优势

下面我们来一步步实现 带头双向循环链表

1.节点空间的创建

如图 这种节点空间里有着两个指针 一个指向next下一个 另一个指向prev上一个

2.链表的初始化

ListNode* BuyNode(LTDatatype x)
{ListNode* node = (ListNode*)malloc(sizeof(ListNode));if(node == NULL){perror("malloc fail");exit(-1);}//开辟好node->data = x;node->next = NULL;node->prev = NULL;return node;
}
ListNode* LTInit(void)
{ListNode* phead = BuyNode(-1);phead->next = phead;phead->prev = phead;return phead;
}

《带头》 不需要一个头指针 直接创建一个节点空间作为哨兵卫头节点

头节点的初始化 prev 和next都指向自己

3.链表 增删查改 接口函数的实现

void LTPushBack(ListNode* phead,LTDatatype x);//尾插
void LTPopBack(ListNode* phead);//尾删
void LTPushFront(ListNode* phead,LTDatatype x);//头插
void LTPopFront(ListNode* phead);//头删
void LTPrint(ListNode* phead);//打印
ListNode* LTFind(ListNode* phead,LTDatatype x);//查找 返回下标
void LTInsert(ListNode* pos,LTDatatype x);//在pos之前插入x
void LTErase(ListNode* pos);//删除pos位置的节点
void LTDestroy(ListNode* phead);//销毁表 防止内存泄漏

函数声明

void LTPushBack(ListNode* phead,LTDatatype x)//尾插
{assert(phead);//切记 phead不能为空 为空则空指针解应用ListNode* newnode = BuyNode(x);//得先找到尾ListNode* ptail = phead->prev;newnode->prev = ptail;newnode->next = phead;ptail->next = newnode;phead->prev = newnode;
}
void LTPrint(ListNode* phead)//打印
{assert(phead);//切记 phead不能为空 为空则空指针解应用ListNode* cur = phead->next;while(cur != phead){//printf("%p,%d,%p",cur->prev,cur->data,cur->next);printf("%d->",cur->data);cur = cur->next;}printf("\n");
}void LTPopBack(ListNode* phead)//尾删
{assert(phead);//切记 phead不能为空 为空则空指针解应用ListNode* tail = phead->prev;ListNode* newtail = tail->prev;newtail->next = phead;phead->prev = newtail;free(tail);}void LTPushFront(ListNode* phead,LTDatatype x)//头插
{assert(phead);//切记 phead不能为空 为空则空指针解应用ListNode* newnode = BuyNode(x);ListNode* next = phead->next;phead->next = newnode;newnode->prev = phead;next->prev = newnode;newnode->next = next;
}void LTPopFront(ListNode* phead)//头删
{assert(phead);//切记 phead不能为空 为空则空指针解应用ListNode* head = phead->next;ListNode* newhead = head->next;phead->next = head->next;newhead->prev = phead;free(head);}
ListNode* LTFind(ListNode* phead,LTDatatype x)//查找 返回下标
{ListNode* cur = phead->next;while(cur != phead){if(cur->data == x){return cur;}cur = cur->next;}return NULL;
}void LTInsert(ListNode* pos,LTDatatype x)
{ListNode* newnode = BuyNode(x);ListNode* next = pos->next;pos->next = newnode;newnode->prev = pos;newnode->next = next;next->prev = newnode;
}void LTErase(ListNode* pos)
{ListNode* next = pos->next;ListNode* prev = pos->prev;prev->next = next;next->prev = prev;free(pos);
}void LTDestroy(ListNode* phead)
{assert(phead);ListNode* cur = phead->next;while (cur != phead){ListNode* next = cur->next;free(cur);cur = next;}free(phead);
}

函数实现

4.注意事项

在实现带头双向循环链表时 我们需要注意这几点

首先是实现一种新的接口函数 出现了bool 布尔类型

bool LTEmpty(ListNode* phead);//判断表中是否为空

使用bool这个关键字需要 头文件包含 #include<stdbool.h>

这个函数会返回true 或 false 来判断表中是否为空

bool LTEmpty(ListNode* phead)
{assert(phead);return phead->next == phead;
}

其次在实现各个接口函数时 千万记得断言 判断phead是否为空

phead作为节点空间 如果被用户误输入为NULL 空进去  空指针解引用 会报错的

最后实现记录表内有多少个元素的函数 用计数器方法即可

size_t LTSize(ListNode* phead);//记录表内元素
size_t LTSize(ListNode* phead)
{assert(phead);size_t size = 0;ListNode* cur = phead->next;//开始遍历 计数器的方法while (cur != phead){size++;cur = cur->next;}return size;
}

总结

带头双向循环链表我们已经实现好了 这种链表十分实用 无论是头插还是尾插 都十分的方便实现

这就是这种结构带来的优势 既然观众老爷们都看到这里了 还不来个一键三连 我们下期见

一起变强!!!

一文搞定带头双向循环链表相关推荐

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

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

  2. 一文搞定 Spring Data Redis 详解及实战

    转载自  一文搞定 Spring Data Redis 详解及实战 SDR - Spring Data Redis的简称. Spring Data Redis提供了从Spring应用程序轻松配置和访问 ...

  3. 一文搞定面试中的二叉树问题

    一文搞定面试中的二叉树问题 版权所有,转载请注明出处,谢谢! http://blog.csdn.net/walkinginthewind/article/details/7518888 树是一种比较重 ...

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

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

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

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

  6. 实现简单的带头双向循环链表

    双向链表 1. 带头双向循环链表的定义 2. 带头双向循环链表的创建 3. 带头双向循环链表的增删改查 (1)头插头删 (2)尾插尾删 (3)pos位置的前插与删除 4.插入与删除改良 1. 带头双向 ...

  7. php带参数单元测试_一文搞定单元测试核心概念

    基础概念 单元测试(unittesting),是指对软件中的最小可测试单元进行检查和验证,这里的最小可测试单元通常是指函数或者类.单元测试是即所谓的白盒测试,一般由开发人员负责测试,因为开发人员知道被 ...

  8. 【Python基础】一文搞定pandas的数据合并

    作者:来源于读者投稿 出品:Python数据之道 一文搞定pandas的数据合并 在实际处理数据业务需求中,我们经常会遇到这样的需求:将多个表连接起来再进行数据的处理和分析,类似SQL中的连接查询功能 ...

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

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

最新文章

  1. Apache Rewrite url重定向功能的简单配置
  2. 【UIKit】解决iOS7状态栏问题
  3. java设计模式 单例_java设计模式一(单例模式singleton)
  4. Selenium2Library关键字(1)
  5. LeetCode 1228. 等差数列中缺失的数字
  6. linux java weblogic,Linux java 安装问题
  7. 操作系统进程间通信简述
  8. js-Tabs小案例
  9. oracle中的代码在那里写,oracle中如何编写树级代码-数据库专栏,ORACLE
  10. axure键盘弹出_AXURE教程:手机键盘
  11. ICD-10/11 查询疾病编码方法
  12. android 5.01,爱思加强版
  13. 【git】基于github开源平台的项目进行二次开发
  14. 数据库系统概论 (王珊.第五版)第七章数据库设计习题答案
  15. 你看到的就是真实的吗?
  16. Mac系统入门之怎么切换输入法
  17. shapenet数据集_三维形状数据的深度特征表示
  18. 计算机专业需要单核还是多核,CPU主频指的是单核还是多核,多核计算机是指计算机有多个CPU-...
  19. Flotherm XT 2021安装说明视频教程
  20. 观江怡之《知识论导论:我们能知道什么?》

热门文章

  1. i18n 是什么,有什么作用
  2. 使Windows Vista中的文件夹始终显示“此处命令提示符”
  3. Cmus终端音乐播放器
  4. Struts2(2)
  5. 计算机操作系统(笔记)
  6. Halcon之Blob分析
  7. 台式电脑计算机的内存叫什么,电脑内存和硬盘有什么区别 电脑内存和硬盘区别介绍【详解】...
  8. 高通发布 Gobi 4000 ,可支持多种制式的通信网络
  9. c语言事故,C语言梆定ActiveX事件
  10. 硬核,用C语言实现面向对象!!!