循环链表(单循环、双循环)(数据结构与算法)

2023-11-05 07:12

本文主要是介绍循环链表(单循环、双循环)(数据结构与算法),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

循环链表:循环单链表、循环双链表

1. 循环单链表

在这里插入图片描述

  1. 循环单链表(Circular Singly Linked List)是一种特殊类型的单链表,其中最后一个节点的指针指向头节点,形成一个循环。

在这里插入图片描述

  1. 循环单链表与普通单链表的主要区别在于,循环单链表的尾节点的指针不是指向 nullptr,而是指向头节点,形成一个闭环。这意味着,在循环单链表中,可以通过尾节点的指针重新回到头节点。

循环单链表可以具有以下特点和优势:

  1. 尾节点的指针指向头节点,使得在遍历链表时不需要特别处理尾节点,方便实现循环遍历。
  2. 可以更容易地进行环形操作,如判断链表是否形成环、寻找环的起始点等。
  3. 循环单链表的插入和删除操作相对简单,因为不需要特别处理头部和尾部情况。
  4. 在使用循环单链表时,我们需要额外关注以下几点:
  5. 在插入和删除节点时,要确保更新指针的正确性,以避免死循环或链表中断。
  6. 在循环单链表中遍历时要设置终止条件,防止进入无限循环。

1.1 初始化一个循环单链表

typedef struct LNode   		//定义单链表结合类型
{ElemType data;			//每个结点存放一个一个数据元素struct LNode *next; 	//指针指向下一个结点
}LNode, *LinkList;//初始化一个循环单链表
bool InitList(LinkList &L)
{L =(LNode *) malloc(sizeof(LNode));	 //分配一个头结点if(L == NULL)  		//内存不足、分配失败return false;L->next = L;		//头结点next指向头结点return true;
}

2.2 判断单链表是否为空

//判断循环单链表是否为空, 检查头结点指针是否指向它自己就行,如下图所示
bool Empty(LinkList L)
{if(L->next == L)  //检查头结点指针是否指向它自己return true;else return false;
}

在这里插入图片描述


2.3 判断 p 结点是否为循环单链表的表尾结点

//判断 p 结点是否为循环单链表的表尾结点
bool isTail(LinkList L, LNode *p)
{if(p->next == L)return true;elsereturn false;
}

在这里插入图片描述

从头结点找到尾部,时间复杂度为O(n), 从尾部找到头部,时间复杂度为O(1), 可以让L指向表尾元素(插入、删除时可能需要修改L)


2. 循环双链表

循环双链表(Circular Doubly Linked List)是一种特殊类型的双向链表,其中最后一个节点的下一个指针指向头节点,头节点的前一个指针指向最后一个节点,形成一个循环。

循环双链表与普通双链表的主要区别在于,循环双链表既具有双向链表的前驱和后继关系,也具有循环遍历的能力。

双链表:表头结点的prior指向NULL; 表尾结点的next指向NULL。

在这里插入图片描述
循环双链表:表头结点的prior指向表尾结点; 表尾结点的next指向头结点。
在这里插入图片描述

2.1循环双链表的特点和优势

  1. 可以通过任意节点的前驱和后继指针方便地在双链表中进行插入和删除操作。
  2. 最后一个节点的下一个指针指向头节点,使得在遍历链表时不需要特别处理尾节点,可以很方便地实现循环遍历。
  3. 可以更容易地进行环形操作,如判断链表是否形成环、寻找环的起始点等。
  4. 循环双链表的插入和删除操作相对简单,不需要特别处理头部和尾部情况。

在插入和删除节点时,要确保更新前驱和后继指针的正确性,以避免链表中断或形成其他错误结构。
在循环双链表中遍历时要设置终止条件,防止进入无限循环。

2.2 循环双链表的初始化

当我们在初始化一个双链表时,需要让头结点的前指针和后指针都指向头结点自己(而普通的双链表指向NULL),如下图所示:

在这里插入图片描述

//初始化空的循环双链表
bool InitDLinkList(DlinkList &L)
{L = (DNode*) malloc(sizeof(DNode));	//分配一个头结点if(L == NULL)		//内存不足,分配失败return false;L->prior = L;    //头结点的prior指向头结点L->next = L;   	//头结点的next指向头结点return true;	//初始化成功
}

2.3 判断循环链表是否为空

typedef struct DNode     //创建循环双链表
{ElemType data;struct DNode *prior,*next;
}DNode, *DLinkList;void testDLinkList()
{//初始化循环双链表DLinkList L;InitDLinkList(L);//.......后续代码.......
}
//判断循环链表是否为空
bool Empty(DLinkList L)
{if(L->next == L)return true;elsereturn false;
}

2.4 判断结点p是否为循环双链表的表尾结点

bool isTail(DLinkList L, DNode  *p)
{if(p->next == L)return true;elsereturn false;
}

2.5 双链表的插入

//在p结点之后插入s结点
bool InsertNextDNode(DNode *p, DNode *s)
{s->next = p->next;	//将结点*s插入到结点*p之后p->next->prior = s;   //如果s->prior = p;p->next = s;
}

在这里插入图片描述

2.6 双链表的删除

//删除p的后继结点q
p->next = q->next;
q->next->prior = p;  //如果p没有后继结点,普通循环链表会出问题
free(q);

在这里插入图片描述

3. 知识回顾

在这里插入图片描述

这篇关于循环链表(单循环、双循环)(数据结构与算法)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/348265

相关文章

Spring 中的循环引用问题解决方法

《Spring中的循环引用问题解决方法》:本文主要介绍Spring中的循环引用问题解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录什么是循环引用?循环依赖三级缓存解决循环依赖二级缓存三级缓存本章来聊聊Spring 中的循环引用问题该如何解决。这里聊

C# foreach 循环中获取索引的实现方式

《C#foreach循环中获取索引的实现方式》:本文主要介绍C#foreach循环中获取索引的实现方式,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录一、手动维护索引变量二、LINQ Select + 元组解构三、扩展方法封装索引四、使用 for 循环替代

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

C#数据结构之字符串(string)详解

《C#数据结构之字符串(string)详解》:本文主要介绍C#数据结构之字符串(string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录转义字符序列字符串的创建字符串的声明null字符串与空字符串重复单字符字符串的构造字符串的属性和常用方法属性常用方法总结摘

SpringBoot实现MD5加盐算法的示例代码

《SpringBoot实现MD5加盐算法的示例代码》加盐算法是一种用于增强密码安全性的技术,本文主要介绍了SpringBoot实现MD5加盐算法的示例代码,文中通过示例代码介绍的非常详细,对大家的学习... 目录一、什么是加盐算法二、如何实现加盐算法2.1 加盐算法代码实现2.2 注册页面中进行密码加盐2.

Java时间轮调度算法的代码实现

《Java时间轮调度算法的代码实现》时间轮是一种高效的定时调度算法,主要用于管理延时任务或周期性任务,它通过一个环形数组(时间轮)和指针来实现,将大量定时任务分摊到固定的时间槽中,极大地降低了时间复杂... 目录1、简述2、时间轮的原理3. 时间轮的实现步骤3.1 定义时间槽3.2 定义时间轮3.3 使用时

Python循环缓冲区的应用详解

《Python循环缓冲区的应用详解》循环缓冲区是一个线性缓冲区,逻辑上被视为一个循环的结构,本文主要为大家介绍了Python中循环缓冲区的相关应用,有兴趣的小伙伴可以了解一下... 目录什么是循环缓冲区循环缓冲区的结构python中的循环缓冲区实现运行循环缓冲区循环缓冲区的优势应用案例Python中的实现库