热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

【C语言教程】“双向循环链表”学习总结及其代码实现

双向循环链表和它名字的表意一样,就是把双向链表的两头连接,使其成为了一个环状链表。只需要将表中最后一个节点的next指针指向头节点,头节点

双向循环链表和它名字的表意一样,就是把双向链表的两头连接,使其成为了一个环状链表。只需要将表中最后一个节点的next指针指向头节点,头节点的prior指针指向尾节点,链表就能成环儿,如图所示:

需要注意的是,虽然双向循环链表成环状,但本质上还是双向链表,因此在双向循环链表中,依然能够找到头指针和头节点等。双向循环链表和双向链表相比,唯一的不同就是双向循环链表首尾相连,其他都完全一样。

注意:因为我上面已经讲了双向链表,所以这里只注重讲他们的实现差异。另因为带头节点会更好操作,所以我的代码都有头节点。

1、双向循环链表的创建

初始化时需要将头节点的next和prior都指向自己。

//1、初始化双向循环链表(带头节点)Status initLinkList(LinkList *list){//创建头节点*list = malloc(sizeof(Node));if (*list == NULL) {return ERROR;}//前驱和后继都指向自己(*list)->prior = *list;(*list)->data = -1;(*list)->next = *list;printf("已初始化链表~\n");return OK;}

2、遍历双向循环链表

注意它的尾节点的next不再是Null,而是头节点//2、遍历双向循环链表void printfLinkLisk(LinkList list){printf("遍历链表:\n");if (list == NULL || list->next == list) {printf("这是一个空链表\n");return;}LinkList p = list;//判断next是否全部正确printf("根据next从前往后遍历:");while (p->next != list) {printf("%d ",p->next->data);p = p->next;}printf("\n");//判断prior是否全部正确printf("根据prior从后往前遍历:");while (p != list) {printf("%d ",p->data);p = p->prior;}printf("\n");}

3、根据索引位置添加节点

这里不需要判断尾节点的next是否为Null&#xff0c;因为它会指向头节点。//3、根据索引位置插入数据至链表中Status insertLinkList(LinkList *list, int index, ElemType data){if (list &#61;&#61; NULL || index <0) {return ERROR;}int i &#61; 0;LinkList priorNode &#61; *list;//判断插入的位置&#xff0c;这里开始位置是0&#xff0c;index超过链表长度则插入末尾while (i next !&#61; *list) {priorNode &#61; priorNode->next;i&#43;&#43;;}LinkList newNode &#61; malloc(sizeof(Node));if (newNode &#61;&#61; NULL) {return ERROR;}newNode->data &#61; data;//插入操作共四步&#xff0c;看好了&#xff0c;别眨眼//1.将priorNode->next节点的前驱指向新节点priorNode->next->prior &#61; newNode;//2.将新节点->next指向原来的priorNode->nextnewNode->next &#61; priorNode->next;//3.将priorNode->next指向新节点priorNode->next &#61; newNode;//4.新节点的前驱指向priorNodenewNode->prior &#61; priorNode;return OK;}

4、根据索引位置删除节点

这里不需要判断尾节点的next是否为Null&#xff0c;因为它会指向头节点。//4、根据索引位置删除节点Status deleteLinkListByIndex(LinkList *list, int index, ElemType *data){if (*list &#61;&#61; NULL || index <0) {return ERROR;}LinkList locaNode &#61; *list;int i &#61; 0;//注意别删了头节点while (i <&#61; index) {locaNode &#61; locaNode->next;if (locaNode &#61;&#61; *list) {printf("没有这个你想要删除的节点\n");return ERROR;}i&#43;&#43;;}//开始删除&#xff0c;只需要做两步locaNode->prior->next &#61; locaNode->next;locaNode->next->prior &#61; locaNode->prior;*data &#61; locaNode->data;free(locaNode);return OK;}

5、根据存储的值删除节点

这里不需要判断尾节点的next是否为Null&#xff0c;因为它会指向头节点。//5、根据存储的值删除节点Status deleteLinkListByData(LinkList *list, ElemType data){if (*list &#61;&#61; NULL) {return ERROR;}LinkList locaNode &#61; (*list)->next;while (locaNode !&#61; *list) {if (locaNode->data &#61;&#61; data) {break;}locaNode &#61; locaNode->next;}if (locaNode &#61;&#61; *list) {printf("没有这个你想要删除的节点\n");return ERROR;}//开始删除&#xff0c;只需要做两步locaNode->prior->next &#61; locaNode->next;locaNode->next->prior &#61; locaNode->prior;free(locaNode);return OK;}

6、根据值查找节点

尾节点的next可是头节点哦&#xff0c;找到它就是最后一个了。//6、查找元素Status selectNode(LinkList list, ElemType data, LinkList *locaNode){if (list &#61;&#61; NULL) {return ERROR;}LinkList p &#61; list->next;while (p !&#61; list) {if (p->data &#61;&#61; data) {*locaNode &#61; p;break;}p &#61; p->next;}if (*locaNode &#61;&#61; NULL) {printf("没有这个你想要的节点\n");return ERROR;}else {return OK;}}

其它代码

#include "stdlib.h"#define OK 1#define ERROR 0//元素类型typedef int ElemType;//状态类型typedef int Status;//定义节点结构体typedef struct Node {struct Node *prior;ElemType data;struct Node *next;} Node;typedef Node *LinkList;int main(int argc, const char * argv[]) {LinkList list;initLinkList(&list);for (int i &#61; 0; i <10; i &#43;&#43;) {insertLinkList(&list, i, i);}printfLinkLisk(list);int index, data;printf("输入你想插入的位置&#xff08;从0开始&#xff09;和存储的值:");scanf("%d %d",&index,&data);insertLinkList(&list, index, data);printfLinkLisk(list);printf("输入你想删除的位置&#xff08;从0开始&#xff09;:");scanf("%d",&index);deleteLinkListByIndex(&list, index, &data);printfLinkLisk(list);printf("输入你想删除的节点的值&#xff08;只删最前的那个&#xff09;:");scanf("%d",&data);deleteLinkListByData(&list, data);printfLinkLisk(list);printf("\n");return 0;}

输出结果&#xff1a;

—END—

看到这里是不是又学到了很多新知识呢~

另外&#xff0c;对于准备学习C/C&#43;&#43;编程的小伙伴&#xff0c;如果你想更好的提升你的编程核心能力&#xff08;内功&#xff09;不妨从现在开始&#xff01;

C语言C&#43;&#43;编程学习交流圈子&#xff0c;QQ群&#xff1a;946108597点击进入】微信公众号&#xff1a;C语言编程学习基地

整理分享&#xff08;多年学习的源码、项目实战视频、项目笔记&#xff0c;基础入门教程&#xff09;

欢迎转行和学习编程的伙伴&#xff0c;利用更多的资料学习成长比自己琢磨更快哦&#xff01;


推荐阅读
  • 学习SLAM的女生,很酷
    本文介绍了学习SLAM的女生的故事,她们选择SLAM作为研究方向,面临各种学习挑战,但坚持不懈,最终获得成功。文章鼓励未来想走科研道路的女生勇敢追求自己的梦想,同时提到了一位正在英国攻读硕士学位的女生与SLAM结缘的经历。 ... [详细]
  • IhaveconfiguredanactionforaremotenotificationwhenitarrivestomyiOsapp.Iwanttwodiff ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • 计算机存储系统的层次结构及其优势
    本文介绍了计算机存储系统的层次结构,包括高速缓存、主存储器和辅助存储器三个层次。通过分层存储数据可以提高程序的执行效率。计算机存储系统的层次结构将各种不同存储容量、存取速度和价格的存储器有机组合成整体,形成可寻址存储空间比主存储器空间大得多的存储整体。由于辅助存储器容量大、价格低,使得整体存储系统的平均价格降低。同时,高速缓存的存取速度可以和CPU的工作速度相匹配,进一步提高程序执行效率。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • c语言\n不换行,c语言printf不换行
    本文目录一览:1、C语言不换行输入2、c语言的 ... [详细]
  • javascript  – 概述在Firefox上无法正常工作
    我试图提出一些自定义大纲,以达到一些Web可访问性建议.但我不能用Firefox制作.这就是它在Chrome上的外观:而那个图标实际上是一个锚点.在Firefox上,它只概述了整个 ... [详细]
  • 本文详细介绍了Linux中进程控制块PCBtask_struct结构体的结构和作用,包括进程状态、进程号、待处理信号、进程地址空间、调度标志、锁深度、基本时间片、调度策略以及内存管理信息等方面的内容。阅读本文可以更加深入地了解Linux进程管理的原理和机制。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • Go语言实现堆排序的详细教程
    本文主要介绍了Go语言实现堆排序的详细教程,包括大根堆的定义和完全二叉树的概念。通过图解和算法描述,详细介绍了堆排序的实现过程。堆排序是一种效率很高的排序算法,时间复杂度为O(nlgn)。阅读本文大约需要15分钟。 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
author-avatar
好人langren_840
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有