当我与单链表分手后,在酒吧邂逅了双向循环链表.....

news2024/11/28 6:39:52

链表的种类有8种,但我们最常用的为无头单向非循环链表带头双向循环链表

带头双向循环链表 

 

当带头双向循环链表只有哨兵位头的时候,双向链表的指向如下图。

 

head->pre和head->next都是指向自己,这个是有巨大优势的,代码实现会很方便。 

1.无头单向非循环链表结构简单,一般不会单独用来存数据。实际中更多是作为其他数据结
构的子结构,如哈希桶、图的邻接表等等。另外这种结构在笔试面试中出现很多。
2. 带头双向循环链表结构最复杂,一般用在单独存储数据。实际中使用的链表数据结构,都
是带头双向循环链表。另外这个结构虽然结构复杂,但是使用代码实现以后会发现结构会带
来很多优势,实现反而简单了,后面我们代码实现了就知道了。

在上个博客实现顺序表和单链表的时候我提过这两点,让我们来进入双向循环链表的实现吧!

带头双向循环链表的结点开辟

LTNode* buynode(SedListtype x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->pre = NULL;
	newnode->next = NULL;

	return newnode;


}

这个开辟结点应该没有什么好说的,带头双向循环链表多了个指针pre。 

带头双向循环链表的初始化

LTNode* LTInit()
{
	LTNode* phead= buynode(-1);
	phead->pre = phead;
	phead->next = phead;
	return phead;

}

哨兵位的结点值是可以随便给的,毕竟只负责站岗,当双向链表为空,phead->pre和phead->next都指向自己,这才是双向循环链表的核心!这里为什么要返回头指针,因为为了与其他增删查改方法实现统一使用一级指针要不然初始化双向链表需要使用二级指针(因为结构体指针是一级指针,为了改变结构体的内容就要传值并用二级指针接受一级指针(结构体指针)才能改变结构体内容),但为了避免问题复杂化,二级指针变为一级指针最简单方法就是自己返回值。

带头双向循环链表的尾插

void LTPushBack(LTNode* phead, SedListtype x)
{
	assert(phead);
	
	LTNode* newnode = buynode(x);
	LTNode* tail = phead->pre;
	tail->next = newnode;
	newnode->pre = tail;
	newnode->next = phead;
	phead->pre = newnode;
}

不用像单链表一样找尾tail,phead->pre就是tail,而且单链表需要判断链表为空不为空的两种情况且需要2级指针,不像带头双向循环链表带有哨兵位的头指针使用一级指针就可以,如果链表为空,这段代码也同样适用,即是头也是尾,双向链表改变的是结构体,用结构体指针就够了,不需要二级指针。

带头双向循环链表为空时

 

带头双向循环链表不为空时 

带头双向循环链表的头插

void LTPushFront(LTNode* phead, SedListtype x)
{
	assert(phead);
	LTNode* newnode = buynode(x);
	LTNode* frist = phead->next;
	phead->next = newnode;
	newnode->pre = phead;
	newnode->next = frist;
	frist->pre = newnode;


}

错误写法
Void LTPushFront(LTNode* phead, LTDataType x)
assert(phead);
LTNode* newnode = BuyLTNode(x);
phead->next = newnode;
newnode->prev = phead;
newnode->next = phead->next;
phead->next->prev = newnode;
最常见错误之一,会找不到phead->next的原来的地址值

调整一下顺序即可
void LTPushFront(LTNode* phead, LTDataType x)
assert(phead);
LTNode* newnode = BuyLTNode(x);
newnode->next = phead->next;
phead->next->prev = newnode;
phead->next = newnode;
newnode->prev = phead;

先保存phead->next头结点的值,避免找不到或者改变phead的值,然后再按照常规连接即可。

当链表为空,这段代码也一样适用,因为双向链表的核心就是头指针的pre和next都是指向自己,这是带头双向循环链表的优势。

 

带头双向循环链表的尾删

void LTPopBack(LTNode* phead)
{
	assert(phead);
	LTNode* tail = phead->pre;
	LTNode* pre = tail->pre;
	free(tail);
	pre->next = phead;
	phead->pre = pre;
}

先找尾tail,然后tail->pre就是上一个结点pre的值,再释放掉尾tail,最后常规连接即可。 

 

带头双向循环链表的头删

void LTPopFront(LTNode* phead)
{
	assert(phead);
	LTNode* frist = phead->next;
	LTNode* second = frist->next;

	phead->next = second;
	second->pre = phead;
	free(frist);

}

头删的代码肯定不止一种写法,但我们这种写法是最通俗易懂且简便的,可以让别人一眼就能看出我们的意图所在,先用frist存phead->next的值,再用second存frist->next的值,然后常规连接释放即可。

 

带头双向循环链表的查找

LTNode* Find(LTNode* phead, SedListtype x)
{
	assert(phead);
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

当cur不等于phead(哨兵位)时就遍历完了链表,这个应该没啥好说的,各位兄弟姐妹也会自己写。但这个查找遍历与顺序表和单链表都一样,查找链表内对应值的内容是可以修改的。 

 带头双向循环链表的插入(pos之前插入)

void LTInsert(LTNode* pos, SedListtype x)
{
	assert(pos);
	LTNode* newnode = buynode(x);
	LTNode* prepos = pos->pre;
	prepos->next = newnode;
	newnode->pre = prepos;
	newnode->next = pos;
	pos->pre = newnode;


}

先用pos->pre找到pos上一个结点的值,再用一个临时变量存储,再常规连接即可。 

 

 

  带头双向循环链表的删除(pos位置删除)

void LTErase(LTNode* pos)
{
	assert(pos);
	LTNode* pospre = pos->pre;
	LTNode* posnext = pos->next;
	pospre->next = posnext;
	posnext->pre = pospre;
	free(pos);

}

 利用pos找出pos前面与后面结点的值,用两个临时变量存储,常规连接两个变量即可。

 

 带头双向循环链表的打印

void LTprint(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	printf("guard<==>");哨兵位
	while (cur != phead)
	{
		printf("%d<==>", cur->data);
		cur = cur->next;
	}
	printf("\n");


}

  带头双向循环链表的销毁

void LTDestory(LTNode* phead)
{
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		LTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
}

用next存储结点值,再一个个释放即可。 

使用完动态开辟的结点值后要销毁,要不然会内存泄漏,phead可以在test.c文件中再置空,因为释放掉以后,不会再有人使用,但为了安全最好在test.c置空一下即可。

带头双向循环链表的完整代码以及运行结果

SedList.h
#include<stdio.h>
#include<assert.h>
#include<stdlib.h>
typedef int SedListtype;
typedef struct SedList
{
	struct SedList* pre;
	struct SedList* next;
	SedListtype data;

}LTNode;

LTNode* LTInit();//初始化;
void LTprint(LTNode* phead);//打印
void LTDestory(LTNode* phead);//销毁

void LTPushBack(LTNode* phead, SedListtype x);//尾插
void LTPushFront(LTNode* phead, SedListtype x);//头插

void LTPopBack(LTNode* phead);//尾删
void LTPopFront(LTNode* phead);//头删

LTNode* Find(LTNode* phead,SedListtype x);//查找

void LTInsert(LTNode* pos, SedListtype x);//pos之前插入
void LTErase(LTNode* pos);//pos位置删除
SedList.c
#include"sedlist.h"
LTNode* buynode(SedListtype x)
{
	LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return NULL;
	}
	newnode->data = x;
	newnode->pre = NULL;
	newnode->next = NULL;

	return newnode;


}
LTNode* LTInit()
{
	LTNode* phead= buynode(-1);
	phead->pre = phead;
	phead->next = phead;
	return phead;

}
void LTprint(LTNode* phead)
{
	assert(phead);
	LTNode* cur = phead->next;
	printf("guard<==>");//哨兵位
	while (cur != phead)
	{
		printf("%d<==>", cur->data);
		cur = cur->next;
	}
	printf("\n");


}
void LTDestory(LTNode* phead)
{
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		LTNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
}

void LTPushBack(LTNode* phead, SedListtype x)
{
	assert(phead);
	
	LTNode* newnode = buynode(x);
	LTNode* tail = phead->pre;
	tail->next = newnode;
	newnode->pre = tail;
	newnode->next = phead;
	phead->pre = newnode;

}

void LTPushFront(LTNode* phead, SedListtype x)
{
	assert(phead);
	LTNode* newnode = buynode(x);
	LTNode* frist = phead->next;
	phead->next = newnode;
	newnode->pre = phead;
	newnode->next = frist;
	frist->pre = newnode;


}

void LTPopBack(LTNode* phead)
{
	assert(phead);
	LTNode* tail = phead->pre;
	LTNode* pre = tail->pre;
	free(tail);
	pre->next = phead;
	phead->pre = pre;
}
void LTPopFront(LTNode* phead)
{
	assert(phead);
	LTNode* frist = phead->next;
	LTNode* second = frist->next;

	phead->next = second;
	second->pre = phead;
	free(frist);



}
LTNode* Find(LTNode* phead, SedListtype x)
{
	assert(phead);
	LTNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

void LTInsert(LTNode* pos, SedListtype x)
{
	assert(pos);
	LTNode* newnode = buynode(x);
	LTNode* prepos = pos->pre;
	prepos->next = newnode;
	newnode->pre = prepos;
	newnode->next = pos;
	pos->pre = newnode;


}
void LTErase(LTNode* pos)
{
	assert(pos);
	LTNode* pospre = pos->pre;
	LTNode* posnext = pos->next;
	pospre->next = posnext;
	posnext->pre = pospre;
	free(pos);

}
test.c
#include"sedlist.h"
void  test1()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);

	LTprint(plist);
	LTDestory(plist);
	plist = NULL;

}
void  test2()
{
	LTNode* plist = LTInit();
	LTPushFront(plist, 1);
	LTPushFront(plist, 2);
	LTPushFront(plist, 3);

	LTprint(plist);
	LTDestory(plist);
	plist = NULL;

}
void  test3()
{
	LTNode* plist = LTInit();
	LTPushBack(plist, 1);
	LTPushBack(plist, 2);
	LTPushBack(plist, 3);
	LTPopBack(plist);
	LTPopBack(plist);
	LTPushBack(plist, 4);
	LTprint(plist);
	LTDestory(plist);
	plist = NULL;

}
void test4()
{
	LTNode* plist = LTInit();
	LTPushFront(plist, 1);
	LTPushFront(plist, 2);
	LTPushFront(plist, 3);
	LTPopFront(plist);
	LTPopFront(plist);
	LTPushFront(plist, 5);
	LTprint(plist);
	LTDestory(plist);
	plist = NULL;

	


}
void test5()
{
	LTNode* plist = LTInit();
	LTPushFront(plist, 1);
	LTPushFront(plist, 2);
	LTPushFront(plist, 3);
	LTPushFront(plist, 5);
	LTNode* pos = Find(plist, 2);
	pos->data = 12;
	LTprint(plist);
	LTDestory(plist);
	plist = NULL;




}
void test6()
{
	LTNode* plist = LTInit();
	LTPushFront(plist, 1);
	LTPushFront(plist, 2);
	LTPushFront(plist, 3);
	LTPushFront(plist, 5);
	LTNode* pos = Find(plist, 2);
	if (pos)
	{
		LTInsert(pos, 24);
	}
	LTprint(plist);
	LTDestory(plist);
	plist = NULL;




}
void test7()
{
	LTNode* plist = LTInit();
	LTPushFront(plist, 1);
	LTPushFront(plist, 2);
	LTPushFront(plist, 3);
	LTPushFront(plist, 5);
	LTNode* pos = Find(plist, 3);
	if (pos)
	{
		LTErase(pos);
	}
	LTprint(plist);
	LTDestory(plist);
	plist = NULL;

}
int main()
{
	test1();
	test2();
	test3();
	test4();
	test5();
	test6();
	test7();

	return 0;
}

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

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

相关文章

CTFHub | 文件包含

0x00 前言 CTFHub 专注网络安全、信息安全、白帽子技术的在线学习&#xff0c;实训平台。提供优质的赛事及学习服务&#xff0c;拥有完善的题目环境及配套 writeup &#xff0c;降低 CTF 学习入门门槛&#xff0c;快速帮助选手成长&#xff0c;跟随主流比赛潮流。 0x01 题目描述…

一篇文章让你上手Canal数据同步神技~

视频教程传送门&#xff1a; Canal极简入门&#xff1a;一小时让你快速上手Canal数据同步神技~_哔哩哔哩_bilibiliCanal极简入门&#xff1a;一小时让你快速上手Canal数据同步神技~共计13条视频&#xff0c;包括&#xff1a;01.课前导学与前置知识点、02.Canal组件了解、03.My…

光纤收发器可以连接光模块吗?

随着科技的进步发展&#xff0c;城市信息化速度的加快&#xff0c;光通信产品在数据中心和安防监控等场景中的运用越来越广泛&#xff0c;而这之间的连接则需要光模块和光纤收发器来实现。很多用户对光模块和光纤收发器的使用有些疑虑&#xff0c;两者该如何连接&#xff1f;又…

2023年5月实时获取地图边界数据方法,省市区县街道多级联动【附实时geoJson数据下载】

首先&#xff0c;来看下效果图 在线体验地址&#xff1a;https://geojson.hxkj.vip&#xff0c;并提供实时geoJson数据文件下载 可下载的数据包含省级geojson行政边界数据、市级geojson行政边界数据、区/县级geojson行政边界数据、省市区县街道行政编码四级联动数据&#xff0…

第7章链接:重定位、可执行目标文件、加载可执行目标文件

文章目录 7.7 重定位7.7.1 重定位表目7.7.2 重定位符号引用重定位PC相关的引用重定位绝对引用 7.8 可执行目标文件7.9 加载可执行目标文件 7.7 重定位 一旦链接器完成了符号解析这一步&#xff0c;它就把代码中的每个符号引用和确定的一个符号定义&#xff08;也就是&#xff…

自学成材的黑客很多,但还是得掌握方法,给你黑客入门与进阶建议

建议一&#xff1a; 黑客七个等级&#xff08;仅供参考&#xff09; 黑客&#xff0c;对很多人来说充满诱惑力。很多人可以发现这门领域如同任何一门领域&#xff0c;越深入越敬畏&#xff0c;知识如海洋&#xff0c;黑客也存在一些等级&#xff0c;参考知道创宇 CEO ic&#…

如何把图片无损放大?教你图片怎么无损放大

随着数字图像技术的不断发展&#xff0c;图片无损放大成为了许多人关注的问题。当我们需要将小图片放大到更大的尺寸时&#xff0c;使用传统的放大方法可能会导致图片失真、模糊等质量问题。那么如何在保持高清晰度和精度的同时进行无损放大&#xff0c;一直是一个备受关注的课…

数字化时代,如何从战略设计到架构来打造智慧银行?

导语 | 随着人工智能、大数据、云计算等技术向纵深发展&#xff0c;数字化转型已成为银行发展的“必答题”。调整战略规划和架构重组、加大信息科技投入、推进科技人才队伍建设、持续推出数字化产品……近年来&#xff0c;深化数字化转型&#xff0c;以科技赋能金融服务已成为不…

【C++初阶】第十三篇:模板进阶(非类型模板参数、模板的特化以及模板的分离编译)

文章目录 一、非类型模板参数二、模板的特化2.1 概念2.2 函数模板特化2.3 类模板特化2.3.1 全特化2.3.2 偏特化/半特化 三、模板的分离编译3.1 什么是分离编译3.2 模板的分离编译3.3 解决方法 四、模板总结 一、非类型模板参数 模板参数类型可分为&#xff1a;类型形参和非类型…

通达信SCTR强势股选股公式,根据六个技术指标打分

SCTR指标(StockCharts Technical Rank)的思路来源于著名技术分析师约翰墨菲&#xff0c;该指标根据长、中、短三个周期的六个关键技术指标对股票进行打分&#xff0c;根据得分对一组股票进行排名&#xff0c;从而可以识别出强势股。 与其他技术指标一样&#xff0c;SCTR的设计…

中国社科院与美国杜兰大学能源管理硕士项目是你职场通关的密码吗

职场是一场没有硝烟的战争&#xff0c;想要在职场取得取胜&#xff0c;就要拥有超能力。从职场小白晋升到管理层一路走来诸多不易&#xff0c;想要坐稳或升得更高&#xff0c;要不断提升自己能力&#xff0c;要不间断地学习。社科院与美国杜兰大学能源管理硕士项目是你通关的密…

navicat连接oracle报错 ORA-28547

报错 原因 Navicat自带的oci.dll并不支持oracle11g 具体操作 1. 先用idea连接oracle&#xff0c;查看oracle版本 select * from v$version; 2. 去官网下载 Instant Client 地址&#xff1a; Oracle Instant Client Downloads 下载 选择对应的版本&#xff08;下载时&#x…

未注册老域名扫描软件-免费未注册老域名挖掘

未注册老域名挖掘教程 在SEO优化中&#xff0c;老域名的价值不言而喻&#xff0c;它们的搜索引擎权重、离线广告效果等都比新域名更高。然而&#xff0c;如何挖掘出高质量的老域名并进行注册并非易事。今天&#xff0c;我们将介绍一款名为“147SEO老域名挖掘软件”的工具&…

【SpringBoot】二:自动配置

文章目录 1.自动配置类2. Import3. AutoConfigurationImportSelector4. AutoConfiguration 1.自动配置类 Spring Boot的自动装配机制会试图根据你所添加的依赖来自动配置你的Spring应用程序。 例如&#xff0c;如果你添加了Mysql依赖&#xff0c;而且你没有手动配置任何DataS…

从今天起,不再为 API 烦恼 !

做技术管理的童鞋&#xff0c;往往会陷入这样一种困境&#xff1a;疲于奔命&#xff0c;到处救火填坑&#xff0c;沟通推进&#xff0c;却挤不出时间思考对团队和项目来说真正重要的事情。 你有没有经历过这样的场景&#xff1a; 1. 下属老是改了接口但不维护文档&#xff0c;屡…

初探高并发—ExecutorCompletionService

初探高并发—ExecutorCompletionService 为什么要引入高并发 众所周知&#xff0c;程序中的代码是从下往下顺序执行的&#xff0c;当我们需要在一个方法中同时执行多个耗时的任务时所消耗时间就会大于等于这些任务消耗的累加时间。那么有没有一种办法可以让这些耗时的任务同时…

微信小程序入门04-后端脚手架搭建

我们上一篇已经介绍了权限系统的库表搭建&#xff0c;光有表还是不够的&#xff0c;我们还需要有一个后台系统和数据库进行交互。搭建后台的时候既需要选择使用什么语言&#xff0c;也需要选择框架。 框架分为前端框架和后端框架。在第一篇微信开发者工具搭建的时候我们其实前…

面试官:什么是防抖和节流?如何实现?应用场景?

防抖 与 节流 大厂面试题分享 面试题库 前后端面试题库 &#xff08;面试必备&#xff09; 推荐&#xff1a;★★★★★ 地址&#xff1a;前端面试题库 web前端面试题库 VS java后端面试题库大全 前言 防抖和节流作为很多大厂的经典面试题&#xff0c;问倒了许多小伙伴&a…

【Python-ESL】python-esl安装

pip install python-esl 时会报错&#xff1a; “error: command ‘swig’ failed with exit status 1” 报错原因是 因为 swig 软件未正确安装&#xff0c;当然对swig的版本也是有要求的&#xff0c;目前测试以下版本没有问题&#xff1a; swig3.0.63 python-ESL1.4.18(app-…

域名年龄查询工具-域名历史查询工具

批量域名历史查询工具 在近几年的网络营销中&#xff0c;老域名已经成为获取网站排名和SEO优化的重要途径。而对于购买这些老域名&#xff0c;了解域名的过往经历&#xff0c;可以帮助我们更好地评估域名的价值&#xff0c;并避免购买不良的域名。因此&#xff0c;今天我们将向…