双向循环链表

双向循环链表是一种较为特殊的链表,也是一种常见的数据结构,其头尾相连,各节点之间可互相访问,在单链表中,只能依次向后访问,无法访问上一个节点,而双链表可以依次向下访问也可向上访问。

链表形式
在这里插入图片描述
双链表有很多节点形象的依次连接在一起,每个节点都由一个数据域和两个指针域构成,尾指针存放着下一个节点的地址,头指针存放着上一个节点的地址,故而形象的使各个节点依次相连。

插入一个节点:

在这里插入图片描述
在1、3节点之间插入节点2,1节点尾指针原本指向3节点,改变其指向,使之指向2节点,2节点的头指针便指向1节点,同理,改变3节点的头指针指向,使之指向2节点,2节点的尾指针指向3节点。

删除一个节点
在这里插入图片描述
例如删除2节点,只需将原3(现2节点)节点的地址赋给1节点的尾指针中,3节点的头指针指向1,再将原2(即删除的节点)节点的指针域释放掉即可

头插

循环双链表的链表头一般没有数据,且一般保持这个位置不动,所以访问数据是从第二个节点开始,如果在链表头后一直插入数据,则第二个节点一直都是新数据,所以其实是对双链表进行的是前插操作。

尾插

如果在链表头插入新数据,那么出现在链表头前面的都是新数据,所以和插在链表尾是一个道理,因为双向循环链表是首尾相连的。

具体代码如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h> typedef struct ListNode
{struct ListNode  *front;int data;struct ListNode* next;
}ListNode;typedef struct List
{ListNode *head;
}List;void init(List* plist)//初始化
{//分配空间plist->head =(ListNode*)malloc(sizeof(ListNode));//让头指针和尾指针都指向自己plist->head->front= plist->head;plist->head->next= plist->head;
}int  data_num(List*  plist)//检查链表节点个数
{ListNode* tem;int  i = 0;for (tem =plist->head->next; tem != plist->head; tem = tem->next){i++;}return i;//返回链表节点个数
}void insert_front(ListNode*  plist, intdata)     //链表头前插
{//分配空间ListNode* cur =(ListNode*)malloc(sizeof(ListNode));//记录链表头尾指针的内容,存放的是一个节点的地址,即tem临时充当这个节点ListNode* tem =plist->next;cur->data = data;plist->next = cur;
//使链表头的尾指针指向新插进来的节点cur->front =plist;//新插进来的节点的头指针指向链表头tem->front =cur;  //使tem节点的头指针指向新插进来的节点cur->next =tem;   //新插进来的尾指针指向tem} void forntinsert_list(List* plist, int data)    //前插入一个节点
{insert_front(plist->head,data);
}void insert_after(ListNode*  plist, intdata)     //链表头后插
{ListNode* cur =(ListNode*)malloc(sizeof(ListNode));ListNode* tem =plist->front; cur->data = data;plist->front = cur; //使链表头的头指针指向新插进来的节点cur->next = plist;  //新插进来的节点的尾指针指向链表头tem->next = cur;    //使tem节点的尾指针指向新插进来的节点cur->front = tem;   //新插进来的头指针指向tem
}void afterinsert_list(List* plist, int data) //后插入一个节点
{insert_after(plist->head,data);
}void  the_insert(List  *plist, int pos, int data)
{int i = 0;ListNode* cur =(ListNode*)malloc(sizeof(ListNode));ListNode* tem =plist->head;int num =data_num(plist);if (pos > num)//所插入数据的位置不能大于节点数,因为是循环链表{printf("插入数据失败\n");return;}for (; i < pos;i++){tem =tem->next;//找到插入新节点的位置}cur->data = data;cur->next =tem->next;//将tem尾指针中存放的内容赋给新节点的尾指针,即新节点的尾指针代替tem的尾指针tem->next->front= cur;//将原tem节点的下一个节点的头指针指向新节点cur->front = tem;//将新节点的头指针指向tem节点tem->next = cur;//将tem的尾指针指向新节点
}void print(List* plist)                   //打印
{ListNode* tem;if (plist->head ==NULL){printf("\n链表已销毁\n");return;}for (tem =plist->head->next; tem != plist->head; tem = tem->next)//双向循环链表的遍历{printf("%d  ", tem->data);}printf("\n");
}void  del(ListNode   *the_plist)       //删除
{the_plist->front->next= the_plist->next;//将该节点尾指针中存放的内容存放到上一个节点的尾指针中the_plist->next->front= the_plist->front;//将该节点头指针中存放的内容存放到下一个节点的头指针中free(the_plist);//释放这个节点
}void  del_front(List  *plist)    //头删
{del(plist->head->next);//删除链表头
} void  del_after(List  *plist)    //尾删
{del(plist->head->front);//删除链表尾
}ListNode* list_reach(List* plist, int data)     //查找
{ListNode* tem;for (tem =plist->head->next; tem != plist->head; tem = tem->next){if (tem->data== data)return  tem;}return NULL;
}void  the_del(List  *plist, int data)     //删除指定的节点
{ListNode* tmp =list_reach(plist, data);if (tmp)del(tmp);
}void  destory(List  *plist)      //销毁链表
{while (plist->head!= plist->head->next){del_front(plist);//依次删头}free(plist->head);//释放最后一个头plist->head = NULL;
}int main()
{//定义一个“链表头”List* first ;init(&first);forntinsert_list(&first,2);forntinsert_list(&first,8);print(&first);afterinsert_list(&first,0);print(&first);the_insert(&first,1, 5);print(&first);the_insert(&first,1, 6);print(&first);the_insert(&first,0, 9);print(&first);forntinsert_list(&first,0);print(&first);int k =data_num(&first);printf("%d个节点\n",k);the_insert(&first,8, 7);print(&first); del_after(&first);print(&first);del_front(&first);print(&first);the_del(&first,6);print(&first);system("pause");return 0;
}

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

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

相关文章

OkHttp透明压缩,收获性能10倍,外加故障一枚

要使用OkHttp&#xff0c;一定要知道它的透明压缩&#xff0c;否则死都不知道怎么死的&#xff1b;或者活也不知道为什么活的不舒坦。反正不是好事。什么叫透明压缩呢&#xff1f;OkHttp在发送请求的时候&#xff0c;会自动加入gzip请求头Accept-Encoding:gzip。所以&#xff0…

块元素、行内块和内联元素_如何删除内联块元素之间的空间?

块元素、行内块和内联元素Introduction: 介绍&#xff1a; This question has become rather popular. How does one remove whitespaces between the inline-block elements? The interesting thing is there are numerous solutions to this but not all of them are easy …

Spring--quartz中cronExpression 的配置方法

Spring--quartz中cronExpression Java代码 字段 允许值 允许的特殊字符 秒 0-59 , - * / 分 0-59 , - * / 小时 0-23 , - * / 日期 1-31 , - * ? / L W C 月份 1-12 或者 JAN-DEC , - * /…

C语言图形库——EasyX基本贴图

在C语言的学习过程中&#xff0c;接触最多的就是黑乎乎的DOS窗口&#xff0c;这也是在消磨学习者的兴趣&#xff0c;学到最后可能还不知道C语言到底能做什么&#xff0c;难道就是输入输出数据吗&#xff1f;当然不是&#xff0c;C的用处很广泛&#xff0c;这里不做讨论。我们能…

一气之下,手撸了一个抖音去水印的工具!

百因必有果说一下我为什么要做个抖音视频去水印工具&#xff0c;其实是因为我的沙雕女友&#xff0c;她居然刚我~有天晚上她在抖音看见一个非常具有 教育意义 的视频&#xff0c;“男人疼媳妇就该承包全部家务活”&#xff0c;然后它就想把视频下载下来&#xff0c;分享到她的姐…

css 隐藏元素 显示元素_使用CSS打印时如何隐藏元素?

css 隐藏元素 显示元素Introduction: 介绍&#xff1a; We have come across many challenges while developing a website or web page and every challenge comes with new learnings. It is a trait of a good developer who develops or creates websites or web pages by…

Java新特性:数据类型可以扔掉了?

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;在很久很久以前&#xff0c;我们写代码时要慎重的考虑变量的数据类型&#xff0c;比如下面这些&#xff1a;枚举&#xff1a…

Spyder:Python中机器学习的强大武器

So, first of all, you would need to install Anaconda distribution which can be downloaded from the link https://www.anaconda.com/download/ (for Windows users only). 因此&#xff0c;首先&#xff0c;您需要安装Anaconda发行版 &#xff0c;可以从链接https://www.…

对内存重叠的深入认识

内存重叠&#xff1a;拷贝的目的地址在源地址范围内。所谓内存重叠就是拷贝的目的地址和源地址有重叠。在函数strcpy和函数memcpy都没有对内存重叠做处理的&#xff0c;使用这两个函数的时候只有程序员自己保证源地址和目标地址不重叠&#xff0c;或者使用memmove函数进行内存拷…

Android特效 五种Toast具体解释

Toast是Android中用来显示显示信息的一种机制&#xff0c;和Dialog不一样的是&#xff0c;Toast是没有焦点的&#xff0c;并且Toast显示的时间有限&#xff0c;过一定的时间就会自己主动消失。 1.默认效果: 代码:Toast.makeText(getApplicationContext(), "默认Toast样式&…

为什么阿里巴巴禁止使用BigDecimal的equals方法做等值比较?

△一个对Coding有着独特追求的人△作者 l Hollis来源 l Hollis&#xff08;ID&#xff1a;hollischuang&#xff09;BigDecimal&#xff0c;相信对于很多人来说都不陌生&#xff0c;很多人都知道他的用法&#xff0c;这是一种java.math包中提供的一种可以用来进行精确运算的类型…

动图演示:手撸堆栈的两种实现方法!

作者 | 王磊来源 | Java中文社群&#xff08;ID&#xff1a;javacn666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;GG_Stone&#xff09;正式开始之前&#xff0c;先和各位朋友聊聊公众号后期的一些打算&#xff0c;后面的文章计划写一些关于数据结构和算法的内容…

多图带你彻底理解Java中的21种锁!

作者 | 悟空聊架构来源 | 悟空聊架构&#xff08;ID&#xff1a;PassJava666&#xff09;本篇主要内容如下&#xff1a;本篇主要内容本篇文章已收纳到我的Java在线文档、 Github我的SpringCloud实战项目持续更新中帮你总结好的锁&#xff1a;序号锁名称应用1乐观锁CAS2悲观锁sy…

杨辉三角——数组解决

杨辉三角如图下所示&#xff0c;每一行的第一个数和最后一个数都为1&#xff0c;每一行中间的数&#xff08;出去第一个和最后一个&#xff09;a等于上一行与其相同列数的数b与数b前面的数之和。例&#xff1a; 第3行第2列的数是3&#xff0c;它就等于第2行第2列的数&#xff…

VS生成的exe文件如何在其他电脑上运行

在VS编译器上编写的程序都会生成一个exe文件&#xff0c;有时候写了一个很装逼的程序想在别人电脑炫耀一下&#xff0c;奈何将这个exe文件拷贝过去并不能运行&#xff0c;直接宣告装逼失败。为此将介绍一下如何将生成的exe文件在其他电脑上运行&#xff0c;步骤如下&#xff1a…

netty websocket 简单消息推送demo

2019独角兽企业重金招聘Python工程师标准>>> 今天心情很不好&#xff01;&#xff01;&#xff01; 原因保密。 这篇是基于"netty与websocket通信demo"。 错误想法&#xff1a;大量客户请求&#xff0c;共用一个worker&#xff0c;来实现推送。 正确作法&…

给 JDK 官方提了一个 Bug,结果...

图 by&#xff1a;石头北京-望京关于作者&#xff1a;程序猿石头(ID: tangleithu)&#xff0c;现任阿里巴巴技术专家&#xff0c;清华学渣&#xff0c;前大疆后端 Leader。背景分享一下之前踩的一个坑&#xff0c;背景是这样的&#xff1a;我们的项目依赖于一个外部服务&#x…

解决exe文件在别人电脑上运行缺失文件情况

这里就以vs2013为例&#xff1a;编译后生成的exe文件拷贝到别人电脑上运行是会弹出一个窗口说缺失MSVCR120.dll和MSVCR120D.dll这两个文件。&#xff08;其他vs版本的编译器在所提示的缺失文件按下述方法也可解决&#xff09;下面就介绍一种方法解决。 1、在VS2013软件中找到MS…

32张图带你彻底搞懂事务和锁!

作者 | 悟空聊架构来源 | 悟空聊架构&#xff08;ID&#xff1a;PassJava666&#xff09;转载请联系授权&#xff08;微信ID&#xff1a;PassJava&#xff09;本篇主要内容如下&#xff1a;本篇主要内容一、事务1.1 什么是事务为单个工作单元而执行的一系列操作。如查询、修改数…

分布式映射与集中式映射_K映射上的表达式映射和组包围

分布式映射与集中式映射In the previous article (Karnaugh Map 2, 3 and 4- variable) we have already discussed the designing of K-Map and various forms in which they are represented based on either they are being mapped for minterm or maxterm. 在上一篇文章( 卡…