双向链表+循环链表

news2024/10/6 14:37:26

循环链表+双向链表

循环链表

循环链表是头尾相接的链表(即表中最后一个结点的指针域指向头结点,整个链表形成一个)(circular linked list)

img

**优点:**从表中任一结点出发均可访问全部结点

循环链表与单链表的主要差别当链表遍历时,判别当前指针p是否指向表尾结点的终止条件不同。在单链表中,判别条件为p!=NULL或p->next=NULL,而循环单链表的判别条件为p!=L或p->next!=L

img

img

img

img

#include<stdio.h>
#include<stdlib.h>

typedef struct Lnode {
	int data;
	struct Lnode* next;
}Lnode,*LinkList;

/*初始化循环单链表*/
Lnode* InitList(LinkList L)
{
	L = (Lnode*)malloc(sizeof(Lnode));
	if (L == NULL)
	{
		//提示分配失败
	}
	L->next = L;
}

//判断循环单链表是否为空 (终止条件为p或p->next是否等于头指针)
int Isempty(LinkList L)
{
	if (L->next == L)
	{
		return 1;
	}
	else {
		return -1;
	}
}

//判断结点p是否为循环单链表的表尾结点
int isTail(LinkList L, Lnode* p)
{
	if (p->next == L)
	{
		return 1;
	}
	else {
		return -1;
	}
}

单链表和循环单链表的比较:
**单链表:**从一个结点出发只能找到该结点后续的各个结点;对链表的操作大多都在头部或者尾部;设立头指针,从头结点找到尾部的时间复杂度=O(n),即对表尾进行操作需要O(n)的时间复杂度;
**循环单链表:**从一个结点出发,可以找到其他任何一个结点;设立尾指针,从尾部找到头部的时间复杂度为O(1),即对表头和表尾进行操作都只需要O(1)的时间复杂度;

双向链表

img

为了克服单链表的这一缺点,老科学家们设计了双向链表(double linked list)是在单链表的每个结点中再设计一个指向其前驱结点的指针域。所以在双向链表中的结点有两个指针域,一个指向直接后继,另一个指向直接前驱。这样链表中有两个不同方向的链。img

img

img

与单循环链表类似双向链表也可以有循环表(首尾相接形成"环"[2个])

让头结点的前驱指针指向链表的最后一个结点

最后一个结点的后继指针指向头结点

img

双向链表结构有对称性(设指针p指向某一个结点)

p->prior->next=p=p->next->prior(前进一步后退一步相当于原地踏步)

在双向链表中有些操作(ListLength,GetElemment等因为只涉及一个方向的指针他们的算法与线性表的相同)但在插入和删除需要修改两个方向上的指针两者的算法复杂度均为O(n)

双向链表的插入

img

img

单链表只需修改两个指针,而双向链表修改四个指针

算法复杂度O(n)img

img

总结

image-20230303213156515

链式存储结构的优点:

  • 结点空间可以动态申请和释放;

  • 数据元素的逻辑次序靠结点的指针来指示,插入和删除不需要移动元素。

链式存储结构的缺点:

  • 存储密度小,每个结点的指针域需额外占用存储空间。当每个结点的数据域所占的字节数不多时,指针域所占的存储空间的比重显得很大。

  • 存储密度是指结点数据本身占用的空间**/结点占用的空间总量**

img

链式存储结构是非随机存取结构。对任一结点的操作都要从头指针依指针链查找到该结点,这增加了算法的复杂度。(对某个结点操作一般要先找到该结点)

img

代码总结

双向链表

#include<stdio.h>
#include<stdlib.h>

typedef struct Lnode {
	int data;                       //数据域
	struct Lnode* prior, * next;    //前驱和后继指针
}DLnode,*DLinkList;

DLnode* InitDLinkList(DLinkList L)
{
	L = (DLnode*)malloc(sizeof(DLnode));
	if (L == NULL)
	{
		return -1;     //分配失败
	}
	else
	{
		L->prior = NULL;    //头指针的前驱指针永远指向NULL
		L->next = NULL;     
	}
	return L;
}

void InsertNextDLnode(DLnode* p, DLnode* s) { //将结点 *s 插入到结点 *p之后
	if (p == NULL || s == NULL) //非法参数
		return;

	s->next = p->next;
	if (p->next != NULL)   //p不是最后一个结点=p有后继结点  
		p->next->prior = s;
	s->prior = p;
	p->next = s;

	return;
}
/*
按位序插入操作:
思路:从头结点开始,找到某个位序的前驱结点,对该前驱结点执行后插操作;
前插操作:
思路:找到给定结点的前驱结点,再对该前驱结点执行后插操作;*/


/*删除*/
/*删除p结点的后继结点*/
void DeleteDLnode_next(DLnode* p)
{
	if (p == NULL) {
		return;
	}
	DLnode* q = p->next;    //找到p的后继结点
	if (q == NULL) {
		return;
	}
	p->next = q->next;
	if (q->next != NULL)  //q不是最后一个结点
	{
		q->next->prior = p;
	}
	free(q);
}

/*销毁一个双向链表*/
void DestotyDLinkList(DLinkList L)
{
	//循环释放各个数据结点
	while (L->next != NULL)
	{
		DeleteDLnode_next(L);  //删除头结点的后继节点
		free(L);   //释放头结点
		L = NULL;
	}
}

/*双链表的遍历操作——前向遍历*/
while (p != NULL)
{
	//对接点p做相应处理,并打印
	p = p->prior;
}

/*双链表的遍历操作——后向遍历*/
while (p != NULL) {
	//对结点p做相应处理,eg打印
	p = p->next;
}

双向循环链表

#include<stdio.h>
#include<stdlib.h>

typedef struct Lnode {
	int data;                       //数据域
	struct Lnode* prior, * next;    //前驱和后继指针
}DLnode, * DLinkList;

/*初始化空的循环双向链表*/
void InitDLinkList(DLinkList L)
{
	L=(DLnode*)malloc(sizeof(DLnode));
	if (L == NULL)
	{
		//提示空间不足,分配失败
		return;
	}
	L->prior = L;    //头结点的前驱&后继指针都指向头结点
	L->next = L;
}

//判断循环双向链表是否为空
int IsEmpty(DLinkList L)
{
	if (L->next == L)
	{
		return 1;
	}
	else return -1;
}

//判断p结点是否为循环双向链表的表尾结点
int IsTail(DLinkList L, DLnode* p) {
	if (p->next == L)
	{
		return 1;
	}
	else return -1;
}

//双向循环链表的插入
void InsertNextDLnode(DLnode* p, DLnode* s)
{
	s->next = p->next;
	p->next->prior = s;
	s->prior = p;
	p->next = s;
}

//双向链表的删除操作
void DeleteDLnode(DLnode* p)
{
	if (p == NULL) {
		return;
	}
	DLnode* q = p->next;    //找到p的后继结点
	if (q == NULL) {
		return;
	}
	p->next = q->next;
	if (q->next != NULL)  //q不是最后一个结点
	{
		q->next->prior = p;
	}
	free(q);
}

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

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

相关文章

精准测试对于覆盖率技术的全新诠释

对于白盒测试有深入研究的技术人员可能会问到&#xff0c;精准测试还是很多用到了覆盖率技术&#xff0c;这些本来不就是有开源的工具吗?下面我们来比较一下&#xff1a; 开源的覆盖率工具&#xff1a; 1、 将所有的测试产生的覆盖率混在一起&#xff0c;不具备快速定位缺陷与…

Pycharm补丁包使用教程

虽然社区版在大多情况下已经够用&#xff0c;但是有很多功能都是没有的&#xff0c;对照起一些教程之类的就很不方便 现在直接教一种简单中的简单的补丁包使用方法 我这里用的是 pycharm 19.2.6 注意右下角的configure 一般别的方法都是 打开&#xff0c;然后添加路径&#…

关于提高PX4抗风性

滚转角速率控制器&#xff1a;&#xff08;MC_ROLLRATE_P&#xff0c; MC_ROLLRATE_I&#xff0c; MC_ROLLRATE_D&#xff09; 滚转角速率控制器&#xff1a;&#xff08;MC_PITCHRATE_P&#xff0c; MC_PITCHRATE_I&#xff0c;MC_PITCHRATE_D&#xff09; 滚转角速率控制器…

php宝塔搭建部署实战CSM会议室预约系统源码

大家好啊&#xff0c;我是测评君&#xff0c;欢迎来到web测评。 本期给大家带来一套基于fastadmin开发的CSM会议室预约系统的源码。感兴趣的朋友可以自行下载学习。 技术架构 PHP7.2 nginx mysql5.7 JS CSS HTMLcnetos7以上 宝塔面板 文字搭建教程 下载源码&#xff0…

5年软测,女朋友跑了俩,2年外包感觉自己废了一半,怎么办?

17年毕业&#xff0c;校招毕业就进入一家软件公司&#xff0c;干了2年的点工&#xff0c;随后进入一家外包公司工作至今&#xff0c;安逸使人堕落不知进取&#xff0c;加之随着近年的环境不景气&#xff0c;谈了多年将要结婚的女朋友也因为我的心态和工资要跟我闹分手我想改变现…

nodejs安装和卸载超详细步骤

安装程序①下载完成后&#xff0c;双击安装包&#xff0c;开始安装&#xff0c;使用默认配置安装一直点next即可&#xff0c;安装路径默认在C:\Program Files下&#xff0c;也可以自定义修改②安装路径默认在C:\Program Files下面&#xff0c;也能够自定义修改&#xff0c;而后…

力扣-2020年最后一次登录

大家好&#xff0c;我是空空star&#xff0c;本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目&#xff1a;1890. 2020年最后一次登录二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.…

ThreadLocal学会了这些,你也能和面试官扯皮了!

前言 我们都知道,在多线程环境下访问同一个共享变量,可能会出现线程安全的问题,为了保证线程安全,我们往往会在访问这个共享 变量的时候加锁,以达到同步的效果,如下图所示。 对共享变量加锁虽然能够保证线程的安全,但是却增加了开发人员对锁的使用技能,如果锁使用不当…

MySql主键id不推荐使用UUID

前言 昨天在某个技术群中&#xff0c;有个老哥发送了一个技术视频&#xff1a;讲的是一个毕业生面试被问&#xff0c;前后端的交互ID是使用自增的吗&#xff1f;为什么不使用UUID&#xff1f;最后的解释是说性能问题&#xff0c;这个引起了我的兴趣&#xff0c;查了一下资料总…

计算机网络安全基础知识4:命令执行漏洞,危害极大,DVWA演示命令注入漏洞攻击网站,防御命令注入执行漏洞,low,medium,high,impossible

计算机网络安全基础知识4&#xff1a;命令执行漏洞&#xff0c;危害极大&#xff0c;DVWA演示命令注入漏洞攻击网站&#xff0c;防御命令注入执行漏洞&#xff0c;low&#xff0c;medium&#xff0c;high&#xff0c;impossible 2022找工作是学历、能力和运气的超强结合体&…

CHAPTER 3 Web HA集群部署 - RHCS

Web HA集群部署 - RHCS1. RHCS介绍2. RHCS的核心功能2.1 负载均衡2.2 高可用2.3 存储3. RHCS集群的组成部分3.1 集群管理器CMAN3.2 资源组管理器rgmanager3.3 集群配置文件管理CCS3.4 保护设备Fencs3.5 分布式锁管理器DLM3.6 集群文件系统GFS3.7 集群配置管理工具Conga4. RHCS历…

白盒测试复习重点

白盒测试白盒测试之逻辑覆盖法逻辑覆盖用例设计方法1.语句覆盖2.判定覆盖(分支覆盖)3.条件覆盖4.判定条件覆盖5.条件组合覆盖6.路径覆盖白盒测试之基本路径测试法基本路径测试方法的步骤1.根据程序流程图画控制流图2.计算圈复杂度3.导出测试用例4.准备测试用例5.例题白盒测试总…

扬帆优配“机器人+”方案加码产业发展,这些股有望高增长

“机器人”发明新需求&#xff0c;2022年中国机器人市场规模约为174亿美元。 美国时刻3月1日&#xff0c;特斯拉在得克萨斯州超级工厂举办投资者日活动&#xff0c;展示了人形机器人Optimus的视频&#xff0c;更夸大的是&#xff0c;视频中的机器人好像在制作另一个机器人&…

更改linux时区、时间

问题描述&#xff1a; MINIO上传失败&#xff0c;错误信息如下&#xff1a; The difference between the request time and the servers time is too large. 原因分析&#xff1a; 系统时区与硬件时区不一致导致的 解决方案&#xff1a; 第一种情况&#xff0c;Time zone时区…

【大数据监控】Prometheus、Node_exporter、Graphite_exporter安装部署详细文档

目录Prometheus简介下载软件包安装部署创建用户创建Systemd服务修改配置文件prometheus.yml启动Prometheusnode exporter下载软件包安装部署添加用户创建systemd服务启动node_exportergraphite_exporter下载软件包安装部署创建systemd服务启动 graphite_exporterPrometheus 简介…

rsync+xinetd+inotify+sersync

一、介绍 1.1、rsync 对比 scp 相同&#xff1a; 都有拷贝的功能不同&#xff1a; rsync:具有增量复制&#xff0c;每次复制的时候&#xff0c;会扫描对端是否在同路径下有我要发送的一样的文件或者目录&#xff0c;如果&#xff0c;如果存在&#xff0c;则不进行复制。边复制&…

【脚本】用于得到某个文件/文件夹所有文件的存储大小(MB单位)

知识点 来自在线转换换算网页&#xff1a;在线文件大小(bit,bytes,KB,MB,GB,TB)转换换算 电脑中存储常用的单位&#xff1a; 1Byte(Byte 字节) 8Bit 1KB (Kilobyte 千字节) 1024Byte 1MB (Megabyte&#xff0c;兆字节&#xff0c;简称“兆”) 1024KB 1GB (Gigabyte&am…

附录3-大事件项目后端-项目准备工作,config.js,一些库的简易用法,main.js

目录 1 一些注意 2 创建数据库 3 项目结构 4 配置文件 config.js 5 参数规则包 hapi/joi与escook/express-joi 5.1 安装 5.2 文档中的demo 5.2.1 定义规则 5.2.2 使用规则 5.3 项目中的使用 5.3.1 定义信息规则 5.3.2 使用规则 6 密码加密包 bcrypt.…

【CSAPP】浮点数

文章目录小数表示练习1练习2IEEE浮点表示数字示例练习1练习2练习3舍人练习1练习2练习3浮点运算C语言中的浮点数练习1练习2浮点数对形如Vx∗2yVx*2^yVx∗2y的有理数进行编码。它对表示非常大的数&#xff08;∣V∣>>0|V|>>0∣V∣>>0&#xff09;、非常接近 0的…

单链表详解

单链表一.概念二.一些类型的创建三.尾插四.头插五.头删尾删六.打印链表七.单链表查找,任意位置插入&#xff0c;任意位置删除八.源代码一.概念 该篇链表博客是按照工程项目的格式来记录的&#xff0c;与平常的算法链表有些许不同&#xff0c;注意区分。 二.一些类型的创建 三.尾…