数据结构单循环链表

news2024/11/28 23:56:49

循环链表的特点是无须增加存储量,仅对表的链接方式稍作改变,即可使得表处理更加方便灵活。

【例】在链表上实现将两个线性表(a1,a2,…,an)和(b1,b2,…,bm)连接成一个线性表(a1,…,an,b1,…bm)的运算。

分析:若在单链表或头指针表示的单循环表上做这种链接操作,都需要遍历第一个链表,找到结点an,然后将结点b1链到an的后面,其执行时间是O(n)。若在尾指针表示的单循环链表上实现,则只需修改指针,无须遍历,其执行时间是O(1)。

相应的算法如下:

LinkListConnect(LinkListA,LinkListB)

{//假设A,B为非空循环链表的尾指针

LinkListp=A->next;//①保存A表的头结点位置

A->next=B->next->next;//②B表的开始结点链接到A表尾

free(B->next);//③释放B表的头结点

B->next=p;//④

returnB;//返回新循环链表的尾指针

}

注意:

①循环链表中没有NULL指针。涉及遍历操作时,其终止条件就不再是像非循环链表那样判别p或p->next是否为空,而是判别它们是否等于某一指定指针,如头指针或尾指针等。

②在单链表中,从一已知结点出发,只能访问到该结点及其后续结点,无法找到该结点之前的其它结点。而在单循环链表中,从任一结点出发都可访问到表中所有结点,这一优点使某些运算在单循环链表上易于实现。今天我们学习单循环链表

在学习单循环链表之前

我们可以对比之前学习的普通的单链表结构

可以看到这里最后一个结点的next域为NULL

那么单循环链表相对比单链表就很简单

将最后一个结点的next域改变为头节点的地址

这样就 可以实现一种循环的概念

那么相比较于普通单链表的来说 

单循环链表对比它的代码就改动比较少

我们可以 预测 在 尾插 尾删 此处有不同

接下来我们直接来进行单循环链表的构造

typedef int ELEM_TYPE;

typedef struct CNode
{
    ELEM_TYPE data;//数据域
    struct CNode *next;//指针域
}CNode, *PCNode;


/*
struct CNode
{
    ELEM_TYPE data;//数据域
    struct CNode *next;//指针域
};
typedef struct CNode CNode;
typedef struct CNode* PCNode;
*/


//可实现的操作:
//初始化
void Init_clist(struct CNode *pclist);

//头插
bool Insert_head(PCNode pclist, ELEM_TYPE val);

//尾插
bool Insert_tail(PCNode pclist, ELEM_TYPE val);

//按位置插
bool Insert_pos(PCNode pclist, int pos, ELEM_TYPE val);

//头删
bool Del_head(PCNode pclist);

//尾删
bool Del_tail(PCNode pclist);

//按位置删
bool Del_pos(PCNode pclist, int pos);

//按值删
bool Del_val(PCNode pclist, ELEM_TYPE val);

//查找 //查找到,返回的是查找到的这个节点的地址
struct CNode *Search(PCNode pclist, ELEM_TYPE val);

//获取有效值个数
int Get_length(PCNode pclist);

//判空
bool IsEmpty(PCNode pclist);

//清空
void Clear(PCNode pclist);

//销毁1 无限头删
void Destroy1(PCNode pclist);

//销毁2 不借助头结点,有两个辅助指针
void Destroy2(PCNode pclist);

//打印
void Show(PCNode pclist);

可以看到这个单循环链表的结构体涉及以及实现代码与单链表基本类似

具体可以参考我上一文实现的单链表 

基础数据结构链表_iccoke的博客-CSDN博客 

这就是和普通单链表唯一不同的地方

我们直接给出单循环链表的实现

重点关注关于尾部的函数操作 其他的函数和普通单链表几乎是相同的

#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
#include "clist.h"


//可实现的操作:
//初始化
void Init_clist(struct CNode *pclist)
{
	//0.安全性处理
	assert(pclist != NULL);

	//1.对pclist指向的头结点里面的成员进行赋值:
	//头结点的数据域不使用,只需要对指针域赋值即可,赋值为自身地址
	pclist->next = pclist;

}

//头插
bool Insert_head(PCNode pclist, ELEM_TYPE val)
{
	assert(pclist != NULL);//保证pclist这个指针 指向的单循环链表的头结点 确确实实存在

	struct CNode *pnewnode = (struct CNode *)malloc(1 * sizeof(struct CNode));
	assert(pnewnode != NULL);
	pnewnode->data = val;  //-> ==(*).

	//合适的插入位置不用找,因为头插就是在头结点后面插,所以使用pclist即可

	pnewnode->next = pclist->next;
	pclist->next = pnewnode;

	return true;
}

//尾插
bool Insert_tail(PCNode pclist, ELEM_TYPE val)
{
	//0.安全性处理
	assert(pclist != NULL);

	//1.购买新节点
	struct CNode *pnewnode = (struct CNode *)malloc(1 * sizeof(struct CNode));
	assert(pnewnode != NULL);
	pnewnode->data = val;

	//2.找到合适的插入位置(也就是说找到在哪一个节点后面插入)
	//尾插,找尾结点,用指针p指向
	//通过判断,确实使用需要前驱的for循环,也就是说,申请一个临时指针p,执行头结点
	struct CNode *p = pclist;
	for(; p->next!=pclist; p=p->next);
	//此时,for循环,跑完,p指向尾结点

	//3.插入即可
	pnewnode->next = p->next;
	p->next = pnewnode;

	return true;
}

//按位置插
bool Insert_pos(PCNode pclist, int pos, ELEM_TYPE val)
{
	//0.安全性处理
	assert(pclist != NULL);
	assert(pos>=0 && pos<=Get_length(pclist));

	//1.购买新节点
	struct CNode *pnewnode = (struct CNode *)malloc(1 * sizeof(struct CNode));
	assert(pnewnode != NULL);
	pnewnode->data = val;

	//2.找到合适的插入位置(也就是说找到在哪一个节点后面插入)
	struct CNode * p = pclist; //判断这个是插入函数,需要使用带前驱的for循环
	for(int i=0; i<pos; i++)
	{
		p=p->next;
	}

	//3.插入即可
	pnewnode->next = p->next;
	p->next = pnewnode;

	return true;
}

//头删
bool Del_head(PCNode pclist)
{
	//0:安全性处理
	assert(pclist != NULL);
	if(IsEmpty(pclist))
	{
		return false;
	}//确保至少存在一个有效节点
	
	//1.找到待删除节点,用指针p指向(头删的话,待删除节点就是第一个有效节点)
	struct CNode *p = pclist->next;

	//2.找到待删除节点的前驱,用指针q指向
	//这里不用处理,因为这里pclist就可以代替q

	//3.跨越指向+释放
	pclist->next = p->next;
	free(p);

	return true;
}


//尾删
bool Del_tail(PCNode pclist)
{
	assert(pclist != NULL);//保证pclist这个指针 指向的单循环链表的头结点 确确实实存在
	if(IsEmpty(pclist))//保证pclist指向的这个头结点 后边存在有效节点
	{
		return false;
	}

	struct CNode *p = pclist;
	for( ; p->next!=pclist; p=p->next);

	struct CNode *q = pclist;
	for(; q->next!=p; q=q->next);

	q->next = p->next;
	free(p);

	return true;
}

//按位置删
bool Del_pos(PCNode pclist, int pos)
{
	//0.assert pclist
	assert(pos >=0 && pos<Get_length(pclist));
	if(IsEmpty(pclist))//保证pclist指向的这个头结点 后边存在有效节点
	{
		return false;
	}

	//1.先找q  从头结点开始出发,向后走pos步
	struct CNode *q = pclist;
	for(int i=0; i<pos; ++i)
	{
		q = q->next;
	}
	//这时q就为

	//2.再找p
	struct CNode *p = q->next;

	//3.跨越指向+释放
	q->next = p->next;
	free(p);

	return true;
}

//按值删
bool Del_val(PCNode pclist, ELEM_TYPE val)
{
	//0.安全性处理

	//1.先需要判断val值,是否存在于单循环链表中
	struct CNode*p = Search(pclist, val);

	//2.若存在,则删除,若不存在,则return false
	if(p == NULL)
	{
		return false;
	}

	//反之,找到val这个待删除节点了,且现在由指针p指针


	//3.找带删除节点的上一个节点,用指针q指向
	struct CNode *q = pclist;
	for(; q->next!=p; q=q->next);

	//4.跨越指向+释放
	q->next = p->next;
	free(p);

	return true;
}

//查找 //查找到,返回的是查找到的这个节点的地址
struct CNode *Search(PCNode pclist, ELEM_TYPE val)
{
	//assert pclist
	//将单循环链表遍历一遍即可,对每一个有效节点都判断一次

	struct CNode *p = pclist->next;
	for(; p!=pclist; p=p->next)
	{
		if(p->data == val)
		{
			return p;
		}
	}

	return NULL;
}

//获取有效值个数
int Get_length(PCNode pclist)
{
	//assert pclist
	//将单循环链表遍历一遍即可,对每一个有效节点都判断一次

	int count = 0;//有效值个数
	struct CNode *p = pclist->next;
	for(; p!=pclist; p=p->next)
	{
		count++;
	}

	return count;;
}

//判空
bool IsEmpty(PCNode pclist)
{
	return pclist->next == pclist;
}

//清空
void Clear(PCNode pclist)
{
	return Destroy1(pclist);
}

//销毁1 无限头删
void Destroy1(PCNode pclist)
{
	while(pclist->next != pclist)
	{
		struct CNode *p = pclist->next;
		pclist->next = p->next;
		free(p);
	}
}

//销毁2 不借助头结点,有两个辅助指针
void Destroy2(PCNode pclist)
{
	assert(pclist != NULL);
	if(IsEmpty(pclist)) //保证至少存在一个有效节点
	{
		return;
	}

	//如果在定义指针q的时候,直接赋值为p->next    则一定一定要保证指针p百分之百存在
	struct CNode *p = pclist->next;
	struct CNode *q = p->next;

	//将头结点断开链接
	pclist->next = pclist;

	while(p!=pclist)
	{
		q = p->next;
		free(p);
		p = q;
	}


}

//打印
void Show(PCNode pclist)
{
	//判定使用不需要前驱的for循环

	struct CNode *p = pclist->next;
	for(; p!=pclist; p=p->next)
	{
		printf("%d ", p->data);
	}
	printf("\n");
}

 

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

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

相关文章

智云通CRM:那些令你无法控制的销售局面(一)

销售的复杂性并不仅仅是指购买者得人数很多。复杂销售的定义在最近的十年里有了突破性的变化和发展&#xff0c;这种变化和发展中出现了很多挑战&#xff0c;不仅业务员&#xff0c;就连业务经理都难以应对。因此&#xff0c;唯有制定简化处理程序的计划才能妥善应对这一局面。…

利用if语句求解成绩等级问题

1 问题 成绩进行划分等级&#xff0c;人工划分容易出错&#xff0c;且数量庞大。 2 方法 public class Text06 { public static void main(String[] args) { int score100; System.out.println("score"); // 1.成绩大于等于85 if (sc…

前端_Vue_4.类与样式绑定、条件渲染

文章目录一、Class与Style绑定1.1. 绑定HTML class1.1.1. 绑定对象1.1.2. 绑定数组1.1.3. 在组件上使用1.2. 绑定内联样式1.2.1. 绑定对象1.2.2. 绑定数组1.2.3. 自动前缀1.2.4. 样式多值二、条件渲染2.1. v-if2.2. v-else2.3. v-else-if2.4. \<template\> 上的 v-if2.5.…

电脑开不了机系统应该如何恢复正常

电脑不仅携带方便&#xff0c;而且功能也十分强大&#xff0c;不过电脑使用时会时不时出现问题&#xff0c;如果电脑开不了机怎么办 怎么回事?这是我们经常会遇到的这种的问题&#xff0c;今天小编就和大家分享电脑开不了机了的原因及解决方法。 工具/原料&#xff1a; 系统…

outlook中抄送操作和163撤回邮件

(1)CC和BCC 电子邮件中的CC 英文全称是 Carbon Copy(抄送)。 电子邮件中的BCC英文全称是 Blind Carbon Copy(暗抄送)。 两者的区别在于在BCC栏中的收件人可以看到所有的收件人名(TO&#xff0c;CC&#xff0c;BCC)&#xff0c;而在TO和CC栏中的收件人看不到BBC的收件人名。 …

Android 代码混淆Proguard

混淆概念 Android代码混淆&#xff0c;又称Android混淆&#xff0c;是伴随着Android系统的流行而产生的一种APP保护技术&#xff0c;用于保护APP不被破解和逆向分析。 在Android的具体表现就是打包时&#xff0c;将项目里的包名、类名、变量名根据混淆规则进行更改&#xff0c…

【POJ No. 1743】音乐主题 Musical Theme

【POJ No. 1743】音乐主题 Musical Theme 北大OJ 题目地址 【题意】音乐旋律被表示为N &#xff08;1≤N ≤20000&#xff09;个音符的序列&#xff0c;它们是[1, 88]内的整数&#xff0c;每个音符都代表钢琴上的一个键。许多作曲家都围绕一个重复的主题谱写音乐&#xff0c;该…

建木HA部署

背景 在建木v2.6.1之前&#xff0c;建木Server仅支持单机部署&#xff0c;如果出现单机故障&#xff0c;难以应用于在线场景&#xff0c;并且单机压力过大时&#xff0c;会影响系统延展性。 什么是HA HA&#xff08;High Availability Cluster&#xff09;是高可用集群系统的…

【软件测试】开发人员不鸟自己?看看资深测试如何做的......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 测试人员经常抱怨开…

jsp+servlet+mysql实现的新闻发布管理系统源码+运行教程+文档

今天给大家演示一下一款由jsp servlet mysql实现的新闻发布管理系统&#xff0c;主要实现了前台游客浏览新闻、评论新闻&#xff0c;后台管理员管理新闻等功能&#xff0c;新闻有热点新闻、最新更新等方式在首页展示&#xff0c;还有幻灯片展示重大新闻等功能&#xff0c;满足了…

一招解决开发环境问题——远程容器开发指南

前言 使用C作为主要开发语言的程序猿们应该会认同搭建开发环境是一件烦人的事情。为了编译一个程序不仅需要下载各种依赖包&#xff0c;还可能面临本地系统不兼容、编译器版本不一致、包版本冲突等各种问题。笔者在运营iLogtail开源社区的过程中发现开发和调试环境问题也是成员…

web网页设计期末课程大作业——HTML+CSS+JavaScript美食餐饮文化主题网站设计与实现

&#x1f468;‍&#x1f393;静态网站的编写主要是用HTML DIVCSS JS等来完成页面的排版设计&#x1f469;‍&#x1f393;,常用的网页设计软件有Dreamweaver、EditPlus、HBuilderX、VScode 、Webstorm、Animate等等&#xff0c;用的最多的还是DW&#xff0c;当然不同软件写出的…

为云原生插上翅膀,天翼云弹性存储CStor-CSI助力容器腾飞

云原生是一种新型技术体系&#xff0c;已成为云计算未来的发展方向&#xff0c;越来越多的数字化项目与云原生紧密相连。作为云原生的基座&#xff0c;容器是必不可少的核心技术。然而&#xff0c;以Docker为代表的容器引擎&#xff0c;并不能满足大批量的容器业务需求&#xf…

推荐一套yyds的Java学习资料(非常经典)

Java 是全球最受欢迎的编程语言之一&#xff0c;在世界编程语言排行榜 TIOBE 中&#xff0c;Java 一直霸占着前三名&#xff0c;有好多年甚至都是第一名。 最近几年&#xff0c;全球约有 1/3 的专业程序员将 Java 作为主要编程语言&#xff0c;这一比例在我国更是高达 1/2&…

CTFSHOW web入门 java反序列化篇 web855

web855 得到源码后看到readObject里面有两条路可以走 1、写文件&#xff0c;文件名固定&#xff0c;文件内容开头固定后面内容可以通过write写入 2、执行命令&#xff0c;但是shellcodoe是不可控的&#xff08;static&#xff09; 如果两条路分开来看都没啥可利用的价值&…

ai绘画新功能上线,说一句话就能生成好看的AI画作

ai绘画可以将自己的图片生成二次元&#xff0c;还可以通过关键词描述生成好看的画作&#xff0c;这些我们都早已尝试过了&#xff0c;并且也玩得不亦乐乎&#xff0c;但AI绘画还能进行语音创作&#xff0c;只需要同AI说一句话&#xff0c;它就能创造出相关的画作&#xff0c;所…

【Linux开发笔记】VSCode+WSL——Windows搭建最轻量便捷的Ubuntu/Linux开发环境

1.概述 我们一般搭建Ubuntu开发环境都是采用VMware或者VirtualBox的虚拟机安装Ubuntu的方案&#xff0c;但是这样的方案会有几个弊端&#xff1a; 安装、启动慢&#xff1b;使用图形桌面时卡顿、鼠标不跟手、打字有延迟&#xff1b;磁盘空间占用比较大&#xff1b;内存资源占用…

安卓开发Android studio学习笔记21:ViewPager两种方式实现引导页

实现引导页一、ViewPager实现引导页第一步&#xff1a;创建三个xml1.page1.xml2.page2.xml3.page3.xml第二步&#xff1a;创建适配器GuideAdapter第三步&#xff1a;创建引导页原点1.activity_guide.xml2.GuideActivity.java二、 ViewPager&#xff08;2&#xff09;实现引导页…

[附源码]Node.js计算机毕业设计电影售票管理系统Express

项目运行 环境配置&#xff1a; Node.js最新版 Vscode Mysql5.7 HBuilderXNavicat11Vue。 项目技术&#xff1a; Express框架 Node.js Vue 等等组成&#xff0c;B/S模式 Vscode管理前后端分离等等。 环境需要 1.运行环境&#xff1a;最好是Nodejs最新版&#xff0c;我…

Docker中的bridge模式,可以这么设置

最近有几个已经就业的小伙伴&#xff0c;过来问千锋健哥关于Docker网络配置的问题&#xff0c;他们在实际开发中还是有些疑问。关于Docker网络这一块的内容确实很多&#xff0c;为了让大家搞清楚这个问题&#xff0c;健哥准备搞几篇系列文章&#xff0c;来为各位小伙伴解惑。这…