数据结构双链表和循环链表

news/2024/9/30 0:13:44 标签: 数据结构, 链表

目录

一、循环链表

循环链表就是首尾相接的的链表,就是尾节点的指针域指向头节点使整个链表形成一个循环,这就弥补了以前单链表无法在后面某个节点找到前面的节点,可以从任意一个节点找到目标节点,但是现在我们就不能像以前那样停止循环时的判断条件是否为NULL了,而是判断是否指向头指针
在这里插入图片描述
在这里插入图片描述
由于我们的操作经常是在链表的首位进行操作,所以我们引进尾指针的概念,这样以后就可以直接找到操作尾节点
在这里插入图片描述
下面是循环单链表的相关代码:

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

//初始化一个循环单链表
bool init_list(CirList& l)
{
	l = new Lnode;//开辟空间作为头节点
	if (l == NULL)return false;
	l->next = l;//头指针的指针域指向自己
	return true;
}

//判断循环单链表是否为空表
bool isEmpty(CirList& l)
{
	if (l->next == l)return true;
	return false;
}

二、双向链表

由于单链表无法逆向检索,循环链表逆向寻找元素时间复杂度也是O(n),所以这里提出双向链表的概念,就是给每个元素一个前驱指针,这样我们就可以直接逆向检索上一个元素了,而且时间复杂度为O(1);双向链表的空表里面两个指针装的都是空指针
在这里插入图片描述

#include<iostream>
using namespace std;
typedef struct Lnode
{
	int data;
	Lnode* next,*prior;
}*DoubList,Lnode;

//初始化一个双向链表
bool init_list(DoubList& l)
{
	l = new Lnode;
	if (l == NULL)return false;
	l->next = NULL;
	l->prior = NULL;
	return true;
}

//双向链表建立(前插法)
bool insert_list(DoubList& l)
{
	init_list(l);
	int x;
	while (cin >> x && x != 0)
	{
		Lnode* p = new Lnode{x,l->next,l};
		if (p == NULL)return false;
		if (l->next)l->next->prior = p;
		l->next = p;
	}
	return true;
}

//双链表建立(后插法)
bool insert_tail_list(DoubList& l)
{
	init_list(l);
	int x;
	Lnode* r =l;
	while (cin >> x && x != 0)
	{
		Lnode* p = new Lnode{ x,NULL,r };
		if (p == NULL)return false;
		r->next = p;
		r = p;
	}
	return true;
}

//按位插入:在i位插入元素e
bool insertElem(DoubList& l, int i, int e)
{
	if (i < 1)return false;
	int j=0;
	Lnode* r = l;
	while (j < i - 1 && r->next != NULL)
	{
		r = r->next;
		j++;
	}
	if (j != i - 1)return false;
	Lnode* p = new Lnode{ e,r->next,r };
	if (r->next)r->next->prior = p;
	r->next = p;
	return true;
}

//按值删除元素e
void deleteElem(DoubList&l,int e)
{
	if (!l->next)cout << "删除失败:链表为空" << endl;
	Lnode* r = l->next;
	while (r)
	{
		if (r->data == e)
		{
			r->prior->next = r->next;
			if (r->next)r->next->prior = r->prior;
			delete r;
			r = NULL;
			return;
		}
		r = r->next;
	}
}

//打印双链表
void print(DoubList l)
{
	Lnode* p=l;
	while (p->next)
	{
		p = p->next;
		cout << p->data << "\t";
	}
	cout << endl;
}

int main()
{
	DoubList l;
	insert_list(l);
	print(l);
	deleteElem(l, 3);
	print(l);
	return 0;
}

三、循环双向链表

即使我们有了双向链表,但是当我们想要在尾节点找到头节点附近某个节点仍然不够快捷,所以就引进了循环双向链表的概念,不过判断条件这些就需要改变:判断结束条件从NULL变为链表名L

#include<iostream>
using namespace std;
typedef struct Lnode
{
	int data;
	Lnode* next,*prior;
}*DoubCirList,Lnode;

//初始化一个循环双向链表
bool init_list(DoubCirList& l)
{
	l = new Lnode;
	if (l == NULL)return false;
	//指针域都指向自身
	l->next = l;
	l->prior = l;
	return true;
}

//双向循环链表建立(前插法)
bool insert_list(DoubCirList& l)
{
	init_list(l);
	int x;
	while (cin >> x && x != 0)
	{
		Lnode* p = new Lnode{x,l->next,l};
		if (p == NULL)return false;
		l->next->prior = p;
		l->next = p;
	}
	return true;
}

//双链表建立(后插法)
bool insert_tail_list(DoubCirList& l)
{
	init_list(l);
	int x;
	Lnode* r =l;
	while (cin >> x && x != 0)
	{
		Lnode* p = new Lnode{ x,l,r };
		if (p == NULL)return false;
		r->next = p;
		r = p;
	}
	return true;
}

//按位插入:在i位插入元素e
bool insertElem(DoubCirList& l, int i, int e)
{
	if (i < 1)return false;
	int j=0;
	Lnode* r = l;
	while (j < i - 1 && r->next != l)
	{
		r = r->next;
		j++;
	}
	if (j != i - 1)return false;
	Lnode* p = new Lnode{ e,r->next,r };
	r->next->prior = p;
	r->next = p;
	return true;
}

//按值删除元素e
void deleteElem(DoubCirList&l,int e)
{
	if (l->next==l)cout << "删除失败:链表为空" << endl;
	Lnode* r = l->next;
	while (r!=l)
	{
		if (r->data == e)
		{
			r->next->prior = r->prior;
			r->prior->next = r->next;
			delete r;
			r = NULL;
			return;
		}
		r = r->next;
	}
}

//打印双链表
void print(DoubCirList l)
{
	Lnode* p=l;
	while (p->next!=l)
	{
		p = p->next;
		cout << p->data << "\t";
	}
	cout << endl;
}

int main()
{
	DoubCirList l;
	insert_tail_list(l);
	print(l);
	return 0;
}

http://www.niftyadmin.cn/n/5683948.html

相关文章

算法题题解:分隔链表

Problem: 86. 分隔链表 题目描述&#xff1a; 给定一个链表和一个值 x&#xff0c;要求将链表重新排列&#xff0c;所有小于 x 的节点放在前面&#xff0c;所有大于或等于 x 的节点放在后面。要求保留节点的相对顺序。 解题思路&#xff1a; 因为是链表而不是数组&#xff0c…

企业级移动应用管理平台哪个好?

在当今数字化转型的浪潮中&#xff0c;企业级移动应用管理平台&#xff08;Enterprise Mobile Application Management, EMAM&#xff09;已成为许多企业提升运营效率、加强团队协作与提高工作灵活性的关键工具。这类平台帮助企业安全、有效地管理和部署移动应用程序&#xff0…

C#基于SkiaSharp实现印章管理(10)

向PDF文件插入印章图片比之前实现的向图片文件插入印章麻烦得多。   最初的想法是使用PDF浏览控件在线打开PDF文件&#xff0c;然后在控件中实现鼠标移动时动态显示印章&#xff0c;点击鼠标时向当前PDF页面的鼠标点击位置插入图片。由于是.net 8的Winform项目&#xff0c;选…

分布式数据库——HBase基本操作

启动HBase: 1.启动hadoop,进入hadoop的sbin中 cd /opt/hadoop/sbin/ 2.初始化namenode hdfs namenode -format 3.启动hdfs ./start-all.sh 4.启动hbase cd /opt/hbase/bin ./start-hbase.sh 5.使用jps查看进程 jps 以下图片则是hbase启动成功~ 运行HBase ./hbase sh…

“卷”智能, 从高质量算力开始

算力即国力&#xff0c;这已是产业共识。 当人工智能浪潮席卷全球之际&#xff0c;大家深刻感受到发展算力产业的重要性和紧迫性&#xff0c;高质量的人工智能算力已经与国家竞争、产业升级和企业转型息息相关。 去年&#xff0c;《算力基础设施高质量发展行动计划》的颁布&a…

PHP的guzzlehttp/guzzle库在碰到各种异常时的场景

PHP的guzzlehttp/guzzle库在碰到各种异常时的场景 结论: 经过测试得知 在http状态码为1xx, 2xx, 3xx时, 会在111处输出返回 在http状态码为4xx, 5xx时, 会在222处被捕获 在目标服务不可达或其他异常时会在333处被捕获 测试过程: 用其他程序写个接口, 实现输入什么状态码就返…

ICML 2024 论文分享┆一个简单且通用的交通预测提示调优框架

论文简介 本推文介绍了2024 ICML的优秀论文之一《FlashST: A Simple and Universal Prompt-Tuning Framework for Traffic Prediction》。论文的核心目标是通过整合空间和时间因素&#xff0c;精准地预测和分析交通流量的动态变化。然而&#xff0c;在交通预测领域&#xff0c…

解读 Story Protocol:IP 与区块链的潜力与障碍

撰文&#xff1a;100y.eth 编译&#xff1a;J1N&#xff0c;Techub News 8 月&#xff0c;据 The Block 报道&#xff0c;专注于知识产权&#xff08;IP&#xff09;的区块链 Story 宣布完成 a16z Crypto 领投 8000 万美元 B 轮融资&#xff0c;参投方包括 Polychain Capital&…