当前位置: 首页 > news >正文

【C 数据结构】循环链表

文章目录

  • 【 1. 基本原理 】
  • 【 2. 循环链表的创建 】
    • 2.1 循环链表结点设计
    • 2.2 循环单链表初始化
  • 【 3. 循环链表的 插入 】
  • 【 4. 循环单链表的 删除操作 】
  • 【 5. 循环单链表的遍历 】
  • 【 6. 实例 - 循环链表的 增删查改 】
  • 【 7. 双向循环链表 】

【 1. 基本原理 】

  • 对于单链表以及双向链表,其就像一个小巷,无论怎么样最终都能从一端走到另一端,然而循环链表则像一个有传送门的小巷,因为循环链表当你以为你走到结尾的时候,其实你又回到了开头。
  • 循环链表和非循环链表其实创建的过程以及思路几乎完全一样,唯一不同的是,非循环链表的尾结点指向空(NULL),而 循环链表的尾指针指向的是链表的开头。通过将单链表的尾结点指向头结点的链表称之为 循环单链表(Circular linkedlist)。如下图所示:
    在这里插入图片描述

【 2. 循环链表的创建 】

2.1 循环链表结点设计

  • 以单循环链表为例,对于循环单链表的结点,可以完全参照于单链表的结点设计,如图:
    • data表示数据,其可以是简单的类型(如int,double等等),也可以是复杂的结构体(struct类型)
    • next表示指针,它永远指向自身的下一个结点, 对于 只有一个结点的存在,这个next指针则永远指向自身,对于一个 循环链表的尾部结点,next永远指向开头。
      在这里插入图片描述
  • 其代码可以表示为:
typedef struct list
{int data;struct list *next;
}list;
//data为存储的数据,next指针为指向下一个结点

2.2 循环单链表初始化

  • 如同单链表的创建,我们需要先创建一个头结点并且给其开辟内存空间,但与单链表不同的是,我们需要在开辟内存空间成功之后将头结点的next指向head自身。我们可以创建一个init函数来完成这件事情,为了以后的重复创建和插入,我们可以考虑 在init重创建的结点next指向空,而在主函数调用创建之后手动 将head头结点的next指针指向自身。这样的操作方式可以方便过后的创建单链表,直接利用多次调用的插入函数即可完成整体创建。
  • C语言实现可以表示为:
//初始结点
list *initlist()
{list *head=(list*)malloc(sizeof(list));if(head==NULL){printf("创建失败,退出程序");exit(0);}else{head->next=NULL;return head;}
}
  • 在主函数重调用:
//初始化头结点
list *head=initlist();
head->next=head;

【 3. 循环链表的 插入 】

  • 对于插入数据的操作,基本与单链表的插入操作相同,我们可以创建一个独立的结点,通过将需要插入的结点的上一个结点的next指针指向该节点,再由需要插入的结点的next指针指向下一个结点的方式完成插入操作。
    在这里插入图片描述
  • C 代码可以表示为:
//插入元素
//三个参数分别是链表,位置,参数
list *insert_list(list *head,int pos,int data)
{list *node=initlist();  //新建结点list *p=head;       //p表示新的链表list *t;t=p;node->data=data;if(head!=NULL){for(int i=1;i<pos;i++){t=t->next;  //走到需要插入的位置处}node->next=t->next;t->next=node;return p;}return p;
}

【 4. 循环单链表的 删除操作 】

  • 如图所示,循环单链表的删除操作可以参考单链表的删除操作,其都是 找到需要删除的结点,将其前一个结点的next指针直接指向删除结点的下一个结点 即可,但需要注意的是尾节点和头结点的特判,尤其是尾结点,因为删除尾节点后,尾节点前一个结点就成了新的尾节点,这个新的尾节点需要指向的是头结点而不是空,其重点可以记录为【删除节点的前一节点.next=删除结点.next】这样的操作可以省去头尾结点的特判:
    在这里插入图片描述
  • C 代码:
//删除元素
int delete_list(list *head) 
{if(head == NULL) {printf("链表为空!\n");return 0;}//建立临时结点存储头结点信息(目的为了找到退出点)//如果不这么建立的化需要使用一个数据进行计数标记,计数达到链表长度时自动退出//循环链表当找到最后一个元素的时候会自动指向头元素,这是我们不想让他发生的list *temp = head; //作为遍历的前一个节点         list *ptr = head->next;//作为遍历的当前节点int del;printf("请输入你要删除的元素:");scanf("%d",&del);while(ptr != head) {if(ptr->data == del) {if(ptr->next == head) //如果是最后一个尾节点{temp->next = head;free(ptr);return 1;}temp->next = ptr->next;    //核心删除操作代码free(ptr);//printf("元素删除成功!\n");return 1;}temp = temp->next;ptr = ptr->next;}printf("没有找到要删除的元素\n");return 0;
}

【 5. 循环单链表的遍历 】

  • 与普通的单链表和双向链表的遍历不同,循环链表需要进行结点的判断,找到尾节点的位置,由于尾节点的next指针是指向头结点的,所以不能使用链表本身是否为空(NULL)的方法进行简单的循环判断,我们需要通过判断结点的next指针是否等于头结点的方式进行是否完成循环的判断
  • 此外还有一种计数的方法,即建立一个计数器count=0,每一次next指针指向下一个结点时计数器加一,当count数字与链表的节点数相同的时候即完成循环,这样做有一个 问题就是获取到链表的节点数同时也需要完成一次遍历才可以达成目标
  • C代码:
//遍历元素
int display(list *head) 
{if(head != NULL) {list *p  = head;//遍历头节点到,最后一个数据while(p->next != head ) {printf("%d   ",p->next->data);p = p->next;}printf("\n");   //习惯性换行//把最后一个节点赋新的节点过去return 1;}else{printf("头结点为空!\n");return 0;}
}

【 6. 实例 - 循环链表的 增删查改 】

 #include<stdio.h>
#include<stdlib.h>
typedef struct list{int data;struct list *next;
}list;
//data为存储的数据,next指针为指向下一个结点//初始结点
list *initlist(){list *head=(list*)malloc(sizeof(list));if(head==NULL){printf("创建失败,退出程序");exit(0);}else{head->next=NULL;return head;}
}//创建--插入数据
int create_list(list *head){int data;   //插入的数据类型printf("请输入要插入的元素:");scanf("%d",&data);list *node=initlist();node->data=data;//初始化一个新的结点,准备进行链接if(head!=NULL){list *p=head;//找到最后一个数据while(p->next!=head){p=p->next;}p->next=node;node->next=head;return 1;}else{printf("头结点已无元素\n");return 0;}}//插入元素
list *insert_list(list *head,int pos,int data){//三个参数分别是链表,位置,参数list *node=initlist();  //新建结点list *p=head;       //p表示新的链表list *t;t=p;node->data=data;if(head!=NULL){for(int i=1;i<=pos;i++){t=t->next;}node->next=t->next;t->next=node;return p;}return p;
}//删除元素
int delete_list(list *head) {if(head == NULL) {printf("链表为空!\n");return 0;}//建立零时结点存储头结点信息(目的为了找到退出点)//如果不这么建立的化需要使用一个数据进行计数标记,计数达到链表长度时自动退出//循环链表当找到最后一个元素的时候会自动指向头元素,这是我们不想让他发生的list *temp = head;          list *ptr = head->next;int del;printf("请输入你要删除的元素:");scanf("%d",&del);while(ptr != head) {if(ptr->data == del) {if(ptr->next == head) { //循环结束的条件换成ptr->next == headtemp->next = head;free(ptr);return 1;}temp->next = ptr->next;free(ptr);//printf("元素删除成功!\n");return 1;}temp = temp->next;ptr = ptr->next;}printf("没有找到要删除的元素\n");return 0;
}//遍历元素
int display(list *head) {if(head != NULL) {list *p  = head;//遍历头节点到,最后一个数据while(p->next != head ) {printf("%d   ",p->next->data);p = p->next;}printf("\n");   //习惯性换行 ( o=^•ェ•)o ┏━┓//把最后一个节点赋新的节点过去return 1;} else {printf("头结点为空!\n");return 0;}
}int main(){//初始化头结点//list *head=initlist();head->next=head;通过插入元素完善链表/for(int i=0;i<5;i++){   //只是演示使用,不具体提供输入create_list(head);}display(head);插入元素head=insert_list(head,1,10);display(head);删除元素delete_list(head);display(head);return 0;
}

【 7. 双向循环链表 】

  • 循环链表还有一个进阶的概念练习,同双向链表与单链表的关系一样,循环单链表也有一个孪生兄弟——双向循环链表,其设计思路与单链表和双向链表的设计思路一样,就是 在原有的双向链表的基础上,将尾部结点和头部结点进行互相连接

相关文章:

【C 数据结构】循环链表

文章目录 【 1. 基本原理 】【 2. 循环链表的创建 】2.1 循环链表结点设计2.2 循环单链表初始化 【 3. 循环链表的 插入 】【 4. 循环单链表的 删除操作 】【 5. 循环单链表的遍历 】【 6. 实例 - 循环链表的 增删查改 】【 7. 双向循环链表 】 【 1. 基本原理 】 对于单链表以…...

Python列表

使用场景&#xff1a;列表是用来存储多组数据的 列表是可变类型 列表支持切片 1.基本规则 1.列表使用[]来表示 2.初始化列表&#xff1a;list [] 3.列表可以一次性存储多个数据&#xff1a;[数据1&#xff0c;数据2&#xff0c;数据3&#xff0c;…] 4.列表中的每一项&#…...

谈谈系列之金融直播展业畅想

近些年直播异常火热&#xff0c;对于各大中小型基金证券公司&#xff0c;也纷纷引入直播作为新型展业渠道。在这其中有一部分直接采用第三方云平台&#xff0c;也有少部分选择自建直播平台。当然自建直播平台也不是纯自研&#xff0c;大抵都是外购第三方厂商整体解决方案&#…...

【C 数据结构】双向链表

文章目录 【 1. 基本原理 】【 2. 双向链表的 创建 】实例 - 输出双向链表 【 3. 双向链表 添加节点 】【 4. 双向链表 删除节点 】【 5. 双向链表查找节点 】【 7. 双向链表更改节点 】【 8. 实例 - 双向链表的 增删查改 】 【 1. 基本原理 】 表中各节点中都只包含一个指针&…...

Leetcode刷题之消失的数字(C语言版)

Leetcode刷题之消失的数字&#xff08;C语言版&#xff09; 一、题目描述二、题目解析 一、题目描述 数组nums包含从0到n的所有整数&#xff0c;但其中缺了一个。请编写代码找出那个缺失的整数。你有办法在O(n)时间内完成吗&#xff1f; 注意&#xff1a;本题相对书上原题稍作…...

LeetCode654:最大二叉树

题目描述 给定一个不重复的整数数组 nums 。 最大二叉树 可以用下面的算法从 nums 递归地构建: 创建一个根节点&#xff0c;其值为 nums 中的最大值。 递归地在最大值 左边 的 子数组前缀上 构建左子树。 递归地在最大值 右边 的 子数组后缀上 构建右子树。 返回 nums 构建的 …...

AI禁区徘徊监测识别摄像机

AI禁区徘徊监测识别摄像机是一种基于人工智能技术的智能监控设备&#xff0c;用于监测禁止进入或逗留的区域。这种摄像机通过高清摄像头实时捕捉场景图像&#xff0c;利用AI算法对人员徘徊行为进行识别和监测&#xff0c;有助于提高安全防范水平&#xff0c;减少潜在的安全风险…...

【学习】什么是信创适配性测试?信创适配性测试的重要性有哪些?

随着信息技术的快速发展和广泛应用&#xff0c;信息技术应用创新&#xff08;信创&#xff09;已成为推动我国产业升级和经济发展的重要力量。在信创领域&#xff0c;适配性测试至关重要&#xff0c;它不仅关系到信创产品的质量和性能&#xff0c;还直接影响到用户的使用体验和…...

linux 配置服务开机启动

一、Centos 中配置进程开启启动 1、使用 systemd 服务&#xff1a; &#xff08;1&#xff09;创建一个名为 myapp.service 的服务文件&#xff1a; [Unit] DescriptionMyApp #描述 After #描述服务类别 [Service] Typefork…...

React中State管理的4 个关键解决方案

在 React 应用开发中,状态(state)管理是非常重要的一部分。合理地管理状态可以确保组件的行为正确,提高应用的可维护性和性能。然而,在实际使用 React 的 state 时,开发者常常会遇到一些常见的问题和陷阱。 本文将从解决问题的角度,总结 React 中 state 管理的4个关键技巧: 使…...

Testng测试框架(6)--@Factory动态地创建测试类的实例

工厂允许您动态地创建测试。例如&#xff0c;假设您想创建一个测试方法&#xff0c;该方法将多次访问网站上的某个页面&#xff0c;并且您希望使用不同的值来调用它。 public class TestWebServer {Test(parameters { "number-of-times" })public void accessPage(…...

Kubernetes(K8s)运维实战:案例解析与代码实践

一、引言 随着容器技术的普及&#xff0c;Kubernetes&#xff08;K8s&#xff09;作为容器编排领域的领军者&#xff0c;已成为企业运维不可或缺的工具。K8s以其强大的自动化管理、可扩展性和高可用性等特点&#xff0c;为运维人员提供了便捷、高效的管理手段。本文将结合具体案…...

nginx反向代理配置详解

首先配置端口 server {listen 3080; server_name 172.20.109.27 localhost;}为了解决刷新后显示404的问题&#xff0c;增加配置如下&#xff1a; location / {root html;index index.html index.htm;try_files $uri $uri.html $uri/ mongrel;}location mongrel {# ip…...

【LeetCode】单调栈类题目详解

所有题目均来自于LeetCode&#xff0c;刷题代码使用的Python3版本 单调栈 通常针对一维数组的问题&#xff0c;如果需要寻找一个元素右边或者左边第一个比自己大或者小的元素的位置&#xff0c;就可以使用单调栈&#xff0c;时间复杂度为O(n) 单调栈的本质是空间换时间&#…...

Python上解决TypeError: not all arguments converted during string formatting错误

目录 背景尝试1: pymysql模块的escape_string方法尝试2: 修改pandas.read_excel引擎尝试3: 回退xlrd版本总结 背景 在Linux上部署的时候, 使用pandas模块读取Excel, 然后pymysql模块入库, 结果发生了错误 Traceback (most recent call last):File "/usr/local/lib64/pyth…...

ASUS华硕ROG幻16Air笔记本电脑GU605M原装出厂Win11系统工厂包下载,带有ASUSRecovery一键重置还原

适用型号&#xff1a;GU605MI、GU605MY、GU605MZ、GU605MV、GU605MU 链接&#xff1a;https://pan.baidu.com/s/1YBmZZbTKpIu883jYCS9KfA?pwd9jd4 提取码&#xff1a;9jd4 华硕原厂Windows11系统带有ASUS RECOVERY恢复功能、自带所有驱动、出厂主题壁纸、系统属性联机支持…...

【OpenVINO™】使用 OpenVINO™ C# API 部署 YOLOv9 目标检测和实例分割模型(上篇)

YOLOv9模型是YOLO系列实时目标检测算法中的最新版本&#xff0c;代表着该系列在准确性、速度和效率方面的又一次重大飞跃。它通过引入先进的深度学习技术和创新的架构设计&#xff0c;如通用ELAN&#xff08;GELAN&#xff09;和可编程梯度信息&#xff08;PGI&#xff09;&…...

代码随想录——二分查找(一)

模版 func BinarySearch(nums *int,target int){l,r:0,len(nums)-1for l<r{mid:l(r-l)/2if nums[mid]target{return mid}else if nums[mid]<target{lmid1}else{rmid-1}}return -1 }特点 查找条件可以在不与元素的两侧进行比较的情况下确定&#xff08;或使用它周围的特…...

【NLP】多标签分类【下】

文章目录 简介个人博客与相关链接1 实验数据与任务说明2 模型介绍2.1 TransformerTransformer能做什么&#xff1f; 2.2 Hugging FaceHugging Face的Transformers库社区支持和资源预训练模型的应用 2.3 T5模型&#xff08;Text-To-Text Transfer Transformer&#xff09;T5的核…...

HWOD:密码强度等级

一、知识点 回车键的ASCII码是10 如果使用EOF&#xff0c;有些用例不通过 二、题目 1、描述 密码按如下规则进行计分&#xff0c;并根据不同的得分为密码进行安全等级划分。 一、密码长度: 5 分: 小于等于4 个字符 10 分: 5 到7 字符 25 分: 大于等于8 个字符 二、字母: 0…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

51c自动驾驶~合集58

我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留&#xff0c;CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制&#xff08;CCA-Attention&#xff09;&#xff0c;…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

C# 求圆面积的程序(Program to find area of a circle)

给定半径r&#xff0c;求圆的面积。圆的面积应精确到小数点后5位。 例子&#xff1a; 输入&#xff1a;r 5 输出&#xff1a;78.53982 解释&#xff1a;由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982&#xff0c;因为我们只保留小数点后 5 位数字。 输…...

10-Oracle 23 ai Vector Search 概述和参数

一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI&#xff0c;使用客户端或是内部自己搭建集成大模型的终端&#xff0c;加速与大型语言模型&#xff08;LLM&#xff09;的结合&#xff0c;同时使用检索增强生成&#xff08;Retrieval Augmented Generation &#…...

安卓基础(aar)

重新设置java21的环境&#xff0c;临时设置 $env:JAVA_HOME "D:\Android Studio\jbr" 查看当前环境变量 JAVA_HOME 的值 echo $env:JAVA_HOME 构建ARR文件 ./gradlew :private-lib:assembleRelease 目录是这样的&#xff1a; MyApp/ ├── app/ …...

React---day11

14.4 react-redux第三方库 提供connect、thunk之类的函数 以获取一个banner数据为例子 store&#xff1a; 我们在使用异步的时候理应是要使用中间件的&#xff0c;但是configureStore 已经自动集成了 redux-thunk&#xff0c;注意action里面要返回函数 import { configureS…...

MFC 抛体运动模拟:常见问题解决与界面美化

在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)

考察一般的三次多项式&#xff0c;以r为参数&#xff1a; p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]&#xff1b; 此多项式的根为&#xff1a; 尽管看起来这个多项式是特殊的&#xff0c;其实一般的三次多项式都是可以通过线性变换化为这个形式…...