带头双向循环链表,顺序表和链表的比较

news2024/11/20 13:42:04

双向链表

单链表结点中只有一个指向其后继的指针,使得单链表只能从前往后依次遍历,要访问某个结点的前驱(插入、删除操作时),只能从头开始遍历,访问前驱的时间复杂度为O(N)。为了克服这个缺点,引入了双链表。

循环链表

循环单链表和单链表的区别在于,表中最后一个结点的指针不是NULL,而改为指向头结点,从而整个链表形成一个环,如图所示。
image.png
在循环单链表中,表尾结点d3的next域指向d1,故表中没有指针域为NULL的结点,因此,循环单链表的判空条件不是头结点的指针是否为空,而是它是否等于头指针d1。

带头双向循环链表的增删查改

带头双向循环链表

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

typedef int LTDataType;

typedef struct ListNode
{
	LTDataType data;
	struct ListNode* next;
	struct ListNode* prev;
}ListNode;

//创建返回链表的头结点
ListNode* BuyLTNode(LTDataType x);

//初始化双向链表
ListNode* ListInit();

//销毁双向链表
void ListDestory(ListNode* phead);

//打印双向链表
void ListPrint(ListNode* phead);

//判断链表是否为空
bool LTEmpty(ListNode* phead);

//查找双向链表
ListNode* LTFind(ListNode* phead, LTDataType x);

//双向链表的头插
void ListPushFront(ListNode* phead, LTDataType x);

//双向链表的尾插
void ListPushBack(ListNode* phead, LTDataType x);

//双向链表的头删
void ListPopFront(ListNode* phead);

//双向链表的尾删
void ListPopBack(ListNode* phead);

//双向链表在pos位置之前的插入
void ListInsert(ListNode* pos, LTDataType x);

//双向链表删除pos位置的结点
void ListErase(ListNode* pos);

双向链表的头插
image.png

#include  "list.h"

//创建返回链表的头结点
ListNode* BuyLTNode(LTDataType x)
{
	ListNode* newnode = (ListNode*)malloc(sizeof(ListNode));
	if (newnode == NULL)
	{
		perror("newnode malloc fail");
		return NULL;
	}

	newnode->data = x;
	newnode->next = NULL;
	newnode->prev = NULL;
	return newnode;
}

//初始化双向链表
ListNode* ListInit() 
{
	ListNode* phead = BuyLTNode(-1);
	phead->next = phead;
	phead->prev = phead;
	return phead;
}

//销毁双向链表
void ListDestory(ListNode* phead) 
{
	assert(phead);

	ListNode* cur = phead->next;
	while (cur != phead)
	{
		ListNode* next = cur->next;
		free(cur);
		cur = next;
	}
	free(phead);
}

//打印双向链表
void ListPrint(ListNode* phead)
{
	assert(phead);
	printf("sentinel《==》");
	ListNode* cur = phead->next;
	while (cur != phead)
	{
		printf("%d《==》", cur->data);
		cur = cur->next;
	}
	printf("\n");
}

//判断链表是否为空
bool LTEmpty(ListNode* phead)
{
	assert(phead);

	return phead->next == phead;//等于就是空
}

//查找双向链表
ListNode* LTFind(ListNode* phead, LTDataType x)
{
	assert(phead);
	ListNode* cur = phead->next;
	while (cur != phead)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return NULL;
}

//双向链表的头插
void ListPushFront(ListNode* phead, LTDataType x)
{
	assert(phead);

	/*
	ListInsert(phead->next,x);//使用 Insert 进行头插
	*/
	ListNode* newnode = BuyLTNode(x);
	ListNode* frist = phead->next;
	
	phead->next = newnode;
	newnode->prev = phead;

	newnode->next = frist;
	frist->prev = newnode;

	/*newnode->next = phead->next;
	phead->next->prev = newnode;
	newnode->prev = phead;
	phead->next = newnode;*/
}

//双向链表的尾插
void ListPushBack(ListNode* phead, LTDataType x)
{
	assert(phead);
	/*
	ListInsert(phead->prev,x);//使用 Insert 进行尾插
	*/
	ListNode* newnode = BuyLTNode(x);
	ListNode* tail = phead->prev;

	newnode->next = phead;
	phead->prev = newnode;
	newnode->prev = tail;
	tail->next = newnode;
}

//双向链表的头删
void ListPopFront(ListNode* phead) 
{
	assert(phead);
	assert(!LTEmpty(phead));//断言条件尽量不写在一起,不然无法判断是其中哪个条件出错

	/*
	ListErase(phead->next);//使用 Erase 进行头删
	*/
	ListNode* frist = phead->next;
	ListNode* fristnext = frist->next;//增加代码的可读性
	free(frist);
	phead->next = fristnext;
	fristnext->prev = phead;

	/*if (frist != phead){
		frist->next->prev = phead;
		phead->next = frist->next;
		free(frist);}*/
}

//双向链表的尾删
void ListPopBack(ListNode* phead)
{
	assert(phead);
	assert(!LTEmpty(phead));
	/*
	ListErase(phead->prev);//使用 Erase 进行尾删
	*/
	ListNode* tail = phead->prev;
	ListNode* tailprev = tail->prev;
	free(tail);
	tailprev->next = phead;
	phead->prev = tailprev;

	/*if (tail != phead){
		phead->prev = tail->prev;
		tail->prev->next = phead;
		free(tail);}*/
}

//双向链表在pos位置之前的插入
void ListInsert(ListNode* pos, LTDataType x) {
	assert(pos);

	ListNode* prev = pos->prev;
	ListNode* newnode = BuyLTNode(x);
	prev->next = newnode;
	newnode->prev = prev;
	newnode->next = pos;
	pos->prev = newnode;
}

//双向链表删除pos位置的结点
void ListErase(ListNode* pos) {
	assert(pos);
	//注意,当pos传递为phead的值时,即哨兵位值时,会出现错误。
	//可将phead传递进来,使pos!=phead,,,否则就干脆不判断,出现错误时再解决
    
	ListNode* prev = pos->prev;
	ListNode* next = pos->next;
	prev->next = next;
	next->prev = prev;
	free(pos);
}
#include  "list.h"

void test1()
{
	ListNode* plist = ListInit();
	ListPushFront(plist, 1);
	ListPushFront(plist, 1);
	ListPushFront(plist, 2);
	ListPushFront(plist, 2);
	ListPushFront(plist, 3);
	ListPushFront(plist, 3);
	ListPushBack(plist, 11);
	ListPushBack(plist, 22);
	ListPrint(plist);
	
	ListPopFront(plist);
	ListPopBack(plist);
	ListPrint(plist);

	ListNode* pos = LTFind(plist,3);
	ListInsert(pos, 33);
	pos = LTFind(plist, 1);
	ListErase(pos);
	ListPrint(plist);

	ListDestory(plist);
    plist = NULL;
}

int main()
{
	test1();
	return 0;
}

image.png

顺序表和链表比较

顺序表的优点:

1.尾插尾删效率不错,
2.下标的随机访问
3.CPU高速缓存命中率会更高(物理空间时连续的)

顺序表的缺点:

1.前面部分插入删除数据,效率低O(N),需要依次挪动数据,物理空间是连续的。
2.连续的物理空间,空间不够,需要扩容。
a.扩容是需要付出代价的
b.一般伴随着空间浪费

链表的优点:

1.任意位置插入删除,O(1)。ex:带头双向循环链表
2.按需申请空间

链表的缺点:

1.不支持下标的随机访问
2.CPU高速缓存命中率会更低

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

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

相关文章

SSM实战项目——哈哈音乐(二)后台模块开发

1、项目准备 ① 引入后台模块&#xff08;hami-console&#xff09;需要的依赖 <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0…

金融贷款批准预测项目

注意&#xff1a;本文引用自专业人工智能社区Venus AI 更多AI知识请参考原站 &#xff08;[www.aideeplearning.cn]&#xff09; 在金融服务行业&#xff0c;贷款审批是一项关键任务&#xff0c;它不仅关系到资金的安全&#xff0c;还直接影响到金融机构的运营效率和风险管理…

LIN总线基础

文章目录 1 什么是LIN 总线&#xff1f;1.1 LIN总线的历史 2.LIN总线的特点3. 应用4 LIN总线基本概念4.1 LIN报文帧结构4.1.1 主节点与从节点4.1.2 调度表4.1.3网络管理4.1.4 帧头结构4.1.4.1 电平 1 什么是LIN 总线&#xff1f; LIN(Local Interconnect Network)是一种低成本…

linux 搭建Samba服务

Samba简介 SAMBA是⼀个实现不同操作系统之间⽂件共享和打印机共享的⼀种SMB协议的免费软件&#xff0c; SMB(Server Message block)协议是window下所使⽤的⽂件共享协议&#xff0c;我们在linux系统或 者其类unix系统当中可以通过samba服务来实现SMB功能。 &#xff08;1&…

Linux离线安装python3(源码编译)

1、下载python包 下载python3.9.6的源码包 python下载 下载后&#xff0c;解压&#xff0c;目录如下&#xff1a; -rw-------. 1 root root 1454 Aug 26 2023 anaconda-ks.cfg -rw-r--r--. 1 root root 25640094 Apr 4 21:52 Python-3.9.6.tgz drwxrwxr…

LC 96.不同的二叉搜索树

96.不同的二叉搜索树 给你一个整数 n &#xff0c;求恰由 n 个节点组成且节点值从 1 到 n 互不相同的 二叉搜索树 有多少种&#xff1f;返回满足题意的二叉搜索树的种数。 示例 1&#xff1a; 输入&#xff1a; n 3 输出&#xff1a; 5 示例 2&#xff1a; 输入&#xff1a;…

配置启动nacos,保姆级教程

下载nacos 下载链接 https://github.com/alibaba/nacos/releases进去下拉&#xff0c;找到下载版本信息。 下载后如图所示。 配置数据库 在我们的conf文件夹中有一个nacos-mysql的数据库文件 我们需要导入数据库&#xff0c;可通过工具Navicat等进行导入。 会有一下几张表…

【面试经典150 | 动态规划】交错字符串

文章目录 写在前面Tag题目来源解题思路方法一&#xff1a;动态规划 写在最后 写在前面 本专栏专注于分析与讲解【面试经典150】算法&#xff0c;两到三天更新一篇文章&#xff0c;欢迎催更…… 专栏内容以分析题目为主&#xff0c;并附带一些对于本题涉及到的数据结构等内容进行…

JAVA毕业设计133—基于Java+Springboot+Vue的网上宠物店商城管理系统(源代码+数据库+12000字论文)

毕设所有选题&#xff1a; https://blog.csdn.net/2303_76227485/article/details/131104075 基于JavaSpringbootVue的网上宠物店商城管理系统(源代码数据库12000字论文)133 一、系统介绍 本项目前后端分离&#xff0c;分为管理员、用户两种角色 1、用户&#xff1a; 注册…

聚合DNS管理系统v1.0全新发布 域名解析管理系统

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 聚合DNS管理系统可以实现在一个网站内管理多个平台的域名解析&#xff0c;目前已支持的域名平台有&#xff1a;阿里云、腾讯云、华为云、西部数码、CloudFlare。本系统支持多用户&…

数据挖掘中的PCA和KMeans:Airbnb房源案例研究

目录 一、PCA简介 二、数据集概览 三、数据预处理步骤 四、PCA申请 五、KMeans 聚类 六、PCA成分分析 七、逆变换 八、质心分析 九、结论 十、深入探究 10.1 第 1 步&#xff1a;确定 PCA 组件的最佳数量 10.2 第 2 步&#xff1a;使用 9 个组件重做 PCA 10.3 解释 PCA 加载和特…

高度不同的流体瀑布css实现方法

商城商品列表 实现瀑布流展示&#xff0c;通过flex或grid实现会导致每行中的列高度一致&#xff0c;无法达到错落有致的感觉&#xff1b; 为此需要用到&#xff1a; CSS columns 属性 columns 属性是一个简写属性&#xff0c;用于设置列宽和列数。 CSS 语法 columns: column-wi…

网络攻防中json序列化漏洞案例,fastjson远程命令执行漏洞原理

网络攻防中json序列化漏洞案例,fastjson远程命令执行漏洞原理。 网络攻防中的JSON序列化漏洞是指当应用程序使用JSON(JavaScript Object Notation)格式来序列化和反序列化对象时,由于不当处理或不安全的编程实践,导致攻击者能够执行恶意操作的安全漏洞。这些操作可能包括远…

成为不可替代的人,优秀到不能被忽视

一、资料描述 本套个人成长资料&#xff0c;大小30.89M&#xff0c;共有21个文件。 二、资料目录 00发刊词 成为不可替代的人.pdf 01累死你的不是工作&#xff0c;是错的职场价值观.pdf 02教你选好行业&#xff0c;远离裁员降薪.pdf 03如何选对公司&#xff0c;让高薪升值…

AJAX —— 学习(一)

目录 一、原生 AJAX &#xff08;一&#xff09;AJAX 介绍 1.理解 2.作用 3.最大的优势 4.应用例子 &#xff08;二&#xff09;XML 介绍 1.理解 2.作用 &#xff08;三&#xff09;AJAX 的特点 1.优点 2.缺点 二、HTTP 协议 &#xff08;一&#xff09;HTTP 介…

【攻防世界】ics-05

php://filter 伪协议查看源码 preg_replace 函数漏洞 1.获取网页源代码。多点点界面&#xff0c;发现点云平台设备维护中心时&#xff0c;页面发生变化。 /?pageindex 输入什么显示什么&#xff0c;有回显。 用php://filter读取网页源代码 ?pagephp://filter/readconvert.…

docker安装、调试qsign签名服务器

go-cqhttp 在 Docker 里早就部署好了&#xff0c;由于没有搭建 qsign 签名服务器&#xff0c;所以迟迟不敢上线。今天终于搞定了在 Docker 下安装 qsign 签名服务器了。这次用的docker市场里找到的镜像&#xff0c;下次找时间制作一个自己的镜像。 1 拉取和运行镜像&#xff1a…

轻薄本没有独立显卡如何运行stable diffusion

众所周知&#xff0c;Stable Diffusion WebUI 使用 GPU 模式运行。 一&#xff1a;检查自己显卡 打开任务管理器或者winR 输入dxdiag 查看自己显卡状态 很明显一般轻薄本只会带有集显&#xff0c;不能满足stable diffusion要求所以我们可以使用cup来运行stable diffusion 在…

转让1000万不良资产处置公司包变更需要多久

随着经济的发展和市场的变化&#xff0c;越来越多的公司需要进行资产的处置和转让&#xff0c;以提言公司的效益和盈利。山东不良资产处置公司作为一家专门服务于资产处置和转让的企业&#xff0c;其流程与变更步骤对于资产转让的操作至关重要。可以致电咨询我或者来公司面谈。…

电荷泵如何实现升压原来

电荷泵如何实现升压原来 某芯片自举栅极驱动内部原理图迪克森电荷泵 某芯片自举栅极驱动内部原理图 迪克森电荷泵 迪克森电荷泵&#xff08;Dickson Charge Pump&#xff09;是一种电压倍增器电路&#xff0c;可以将低电压升高到较高电压&#xff0c;相对于其他电压升压电路&a…