循环链表的实现

循环链表简介

简单来说,单链表像一个小巷,无论怎么样最终都能从一端走到另一端,循环链表则像一个有传送门的小巷,因为循环链表当你以为你走到结尾的时候,其实你又回到了开头。循环链表和非循环链表其实创建的过程以及思路几乎完全一样,唯一不同的是,非循环链表的尾结点指向空(NULL),而循环链表的尾指针指向的是链表的开头。通过将单链表的尾结点指向头结点的链表称之为循环单链表(Circular linkedlist)。
在这里插入图片描述
如上图所示,循环链表将单链表中终端结点的指针端由空指针改为指向头结点,就使整个单链表形成一个环。循环链表与单链表的主要差异在于循环的判断上,原来是判断p->next是否为空,现在则是p->next不等于头结点,则循环未结束。

循环链表的实现

1、创建链表

如同单链表的创建,我们需要先创建一个头结点并且给其开辟内存空间,但与单链表不同的是,我们需要在开辟内存空间成功之后将头结点的next指向head自身。当需要进行插入时,我们首先创建一个新的节点,将原有链表尾结点的next指针修改指向到新的结点,新结点的next指针再重新指向头部结点,然后逐步进行这样的插入操作,最终完成整个单项循环链表的创建。代码示例如下:

int insert_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;  
    }  
}  

2、删除操作

如图2所示,循环单链表的删除操作可以参考单链表的删除操作,其都是找到需要删除的结点,将其前一个结点的next指针直接指向删除结点的下一个结点即可,但需要注意的是尾节点和头结点的特判,尤其是尾结点,因为删除尾节点后,尾节点前一个结点就成了新的尾节点,这个新的尾节点需要指向的是头结点而不是空,其重点可以记录为当前的前一节点.next=自身结点.next这样的操作可以省去头尾结点的特判。
在这里插入图片描述
示例代码:

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;  
}  

循环链表删除功能的实现:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include<stdlib.h>
#define ERROR 0
#define OK 1
typedef int EleType;
typedef struct CLinkNode
{
	EleType data;
	struct CLinkNode *next;
}CLinkNode,*CLinkList;
 
/*
初始化循环链表
*/
int InitCLinkList(CLinkList *list)
{
	if (list == NULL)
	{
		return ERROR;
	}
 
	int data = 0;
	CLinkNode* target = NULL;
	CLinkNode* head_node = NULL;
	printf("输入结点数据中...\n");
	while (1)
	{
		scanf("%d", &data);
		if (data == 0)
		{
			//退出循环标志,用户输入0 表示结束输入数据
			break;
		}

		if (*list == NULL)
		{
			CLinkNode* head= (CLinkNode*)malloc(sizeof(CLinkNode));
			//分配结点空间失败
			if (head == NULL)
			{
				exit(0);
			}
 
			*list = head;//链表指向头结点
 
			CLinkNode* node = (CLinkNode*)malloc(sizeof(CLinkNode));
			if (node == NULL)
			{
				exit(0);
			}
			node->data = data;
			node->next = head;
			head->next = node;
		}
		else
		{
			for (target = (*list)->next; target->next != *list; target = target->next);
			head_node = target->next;
 
			CLinkNode* node = (CLinkNode*)malloc(sizeof(CLinkNode));
			if (node == NULL)
			{
				exit(0);
			}
			node->data = data;
			node->next = head_node;
 
			target->next = node;//将新结点插入尾部
		}
 
	}
	return OK;
}
/*
往链表指定位置插入数据
list 循环链表
loc 第loc位置插入元素,loc 从1 开始计数
data 插入元素的数据域
*/
int InsertCLinkNode(CLinkList list,int loc, EleType data)
{
	if (list == NULL || loc < 1)
		return ERROR;
	/*
	循环目的:找到第loc-1位置结点
	*/
	int i = 1;
	CLinkNode* node = list;//刚开始node指向头结点
	while (node->next!=list && i < loc)
	{
		node = node->next;
		i++;
	}
	if (i == loc)
	{
		CLinkNode* new_node = (CLinkNode*)malloc(sizeof(CLinkNode));
		if (new_node == NULL)
		{
			exit(0);
		}
		new_node->data = data;
		new_node->next = node->next;//新结点指针域 指向前驱结点的后继结点
		node->next = new_node;//将新结点加入链表
	}
	else
	{
		return	ERROR;
	}
 
	return OK;
}
/*
删除指定结点,通过指针返回删除结点的数据,并保存至data
*/
int DelCLinkNode(CLinkList list,int loc, EleType* data)
{
	if (list == NULL || loc < 1)
		return ERROR;
	/*
	循环目的:找到第loc-1位置结点
	*/
	int i = 1;// 按人类的读法 i表示第i个位置 和 loc 表达意思一致
	CLinkNode* node = list;//刚开始node指向头结点
	while (node->next != list && i < loc)
	{
		node = node->next;
		i++;
	}
	//循环结束 node 指向 loc-1 位置 且 node 不能为尾结点,为什么不能为尾结点?因为不能删除 位置上没有元素的结点!
	if (i == loc && node->next != list)
	{
        // 请在下面的Begin-End之间补充代码,完成对结点的删除。
        /********** Begin *********/
        CLinkNode* del_node = node->next; //第loc位置的结点
        *data = del_node->data; //返回删除结点的数据域
        node->next = del_node->next; //删除结点的前驱结点指向删除节点的后继结点
        free(del_node);
        /********** End **********/
 
	}
	return OK;
}
/*
展示循环链表元素
*/
int ShowCLinkList(CLinkList list)
{
	if (list == NULL)
	{
		return ERROR;
	}
	CLinkNode* target = NULL;
	
	for (target = list->next; target != list; target = target->next)
		printf("%d \t",target->data);
	printf("\n");
	return OK;
}
int main(int argc, char *argv[])
{
	int flag = 0;
	CLinkList list = NULL;
	list = NULL;
	InitCLinkList(&list);
	printf("--------循环链表初始元素------\n");
	ShowCLinkList(list); 
	int loc = 2;
	int data = 0;
	DelCLinkNode(list, loc, &data);
	printf("--------删除第二个结点后------\n");
	ShowCLinkList(list); 
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

程序员基础知识—IP地址

文章目录 一、什么是IP地址二、IP地址的分类三、子网掩码 一、什么是IP地址 IP地址就像我们需要打电话时的电话号码一样&#xff0c;它用来标识网络中的一台主机&#xff0c;每台主机至少有一个IP地址&#xff0c;而且这个IP地址是全网唯一的。IP地址由网路号和主机号两部分组…

Elasticsearch/Enterprise Search/Kibana安装记录

目录 Elasticsearch的安装导入 elasticsearch PGP密钥 安装使用APT安装手动下载安装 启动elasticsearch安全功能重新配置节点以加入现有集群启用系统索引的自动创建功能运行Elasticsearch(在systemd下)检查Elasticsearch是否正在运行Elasticsearch配置外网访问 第三方包安装ela…

Python学习(十六)柱状图

zdaPython学习&#xff08;十四&#xff09;折线图开发_yikuaidabin的博客-CSDN博客 案例数据资源 ↑ """演示基础柱状图的开发 """ from pyecharts.charts import Bar from pyecharts.options import LabelOpts # 使用Bar构建基础柱状图 bar …

【网络】socket——TCP网络通信 | 日志功能 | 守护进程

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《网络》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 上篇文章中本喵介绍了UDP网络通信的socket代码&#xff0c;今天介绍TCP网络通信的socket代码。 TCP &a…

深度理解 Spring AOP

一、什么是AOP(面向切面编程)&#xff1f;&#x1f349; AOP 为 Aspect Oriented Programming 的缩写&#xff0c;意思为面向切面编程&#xff0c;是通过预编译方式 和运行期 动态代理 实现程序功能的统一维护的一种技术。 AOP &#xff08;面向切面编程&#xff09;是 OOP&a…

深度理解 Spring IOC

Spring容器高层视图 Spring 启动时读取应用程序提供的Bean配置信息&#xff0c;并在Spring容器中生成一份相应的Bean配置注册表&#xff0c;然后根据这张注册表实例化Bean&#xff0c;装配好Bean之间的依赖关系&#xff0c;为上层应用提供准备就绪的运行环境。 Bean缓存池&…

OJ练习第143题——二叉树展开为链表

二叉树展开为链表 力扣链接&#xff1a;114. 二叉树展开为链表 题目描述 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终…

postman批量执行请求,通过json传参

1、创建请求 "authUid":"{{authUid}}", 加粗为需要替换的参数 2、组装JSON 可通过Excel自动填充功能构造数据 [ {"authUid":"18700000001"}, {"authUid":"18725929202"} ] 3、批量执行请求配置 4、然后start r…

PuTTY连接服务器报错Connection refused

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

Cloudreve搭建云盘系统,并实现随时访问

文章目录 1、前言2、本地网站搭建1.环境使用2.支持组件选择3.网页安装4.测试和使用5.问题解决 3、本地网页发布1.cpolar云端设置2.cpolar本地设置 4、公网访问测试5、结语 1、前言 自云存储概念兴起已经有段时间了&#xff0c;各互联网大厂也纷纷加入战局&#xff0c;一时间公…

RabbitMQ惰性队列使用

说明&#xff1a;惰性队列是为了解决消息堆积问题&#xff0c;当生产者生产消息的速度远高于消费者消费消息的速度时&#xff0c;消息会大量的堆积在队列中&#xff0c;而队列中存放的消息数量是有限的&#xff0c;当超出数量时&#xff0c;会造成消息的丢失。而扩容队列&#…

uniapp app运行到ios详细流程

uniapp运行到IOS真机调试&#xff08;windows系统&#xff09; 工具步骤1.首先数据线连接电脑和手机2.右键点击桌面上的HBuilder&#xff0c;打开文件所在位置3.打开HBuilder编辑器里要运行的项目&#xff0c;点击运行>运行到手机或模拟器>运行到IOS APP基座>勾选你的…

LangChain大型语言模型(LLM)应用开发(五):评估

LangChain是一个基于大语言模型&#xff08;如ChatGPT&#xff09;用于构建端到端语言模型应用的 Python 框架。它提供了一套工具、组件和接口&#xff0c;可简化创建由大型语言模型 (LLM) 和聊天模型提供支持的应用程序的过程。LangChain 可以轻松管理与语言模型的交互&#x…

【每日一题】——C - Standings(AtCoder Beginner Contest 308 )

&#x1f30f;博客主页&#xff1a;PH_modest的博客主页 &#x1f6a9;当前专栏&#xff1a;每日一题 &#x1f48c;其他专栏&#xff1a; &#x1f534; 每日反刍 &#x1f7e1; C跬步积累 &#x1f7e2; C语言跬步积累 &#x1f308;座右铭&#xff1a;广积粮&#xff0c;缓称…

ArcGIS、ENVI、InVEST、FRAGSTATS等多技术融合提升环境、生态、水文、土地、土壤、农业、大气等领域的数据分析

一、 空间数据获取与制图 1.1 软件安装与应用讲解 1.2 空间数据介绍 1.3海量空间数据下载 1.4 ArcGIS软件快速入门 1.5 Geodatabase地理数据库 二、 ArcGIS专题地图制作 2.1专题地图制作规范 2.2 空间数据的准备与处理 2.3 空间数据可视化&#xff1a;地图符号与注记 …

十一、正则表达式详解:掌握强大的文本处理工具(三)

文章目录 &#x1f340;贪婪模式&#x1f340;应用的场景&#x1f340;总结 &#x1f340;非贪婪模式&#x1f340;应用的场景&#x1f340;总结 &#x1f340;贪婪模式与非贪婪模式在爬虫的应用&#x1f340;转义字符&#x1f340;正则表达式常见函数 &#x1f340;贪婪模式 在…

如何查看小程序的APPID和AppSecret

小程序APPID可以在手机上打开小程序后&#xff0c;点击右上角三点&#xff1a; 然后点击中间位置的小程序名称&#xff0c;进入小程序介绍页面&#xff1a; 点击“更多资料”后&#xff0c;进入页面就可以看到上方有APPID&#xff1a; 另一种方法&#xff1a; 在微信公众平台登…

【iOS】CALayer的理解与简单使用

文章目录 前言一、UIView与CALayer的关系二、CALayer的简单使用1.圆角与裁剪2.contents3.边框属性 总结 前言 在实现网易云音乐demo开发的过程中&#xff0c;通过查阅网上资料&#xff0c;发现了我们可以对我们的视图进行裁剪来实现美观的体现&#xff0c;例如这样&#xff1a…

Vue--》打造个性化医疗服务的医院预约系统(三)

今天开始使用 vue3 + ts 搭建一个医院预约系统的前台页面,因为文章会将项目的每一个地方代码的书写都会讲解到,所以本项目会分成好几篇文章进行讲解,我会在最后一篇文章中会将项目代码开源到我的GithHub上,大家可以自行去进行下载运行,希望本文章对有帮助的朋友们能多多关…

C语言程序运行需要的两大环境《C语言进阶》

目录 程序的翻译环境和执行环境 翻译环境分为两部分&#xff0c;编译链接 第一步&#xff1a;预编译&#xff08;预处理&#xff09; 第二步&#xff0c;编译 第三步&#xff1a;汇编 关于运行环境分为四点&#xff1a; 关于链接库 程序的翻译环境和执行环境 在 ANSI C(标…