[数据结构]带头双向循环链表的实现与应用

news2024/12/25 18:42:47

文章目录

  • 一、引言
  • 二、链表的基本概念
    • 1、链表是什么
    • 2、链表与顺序表的区别
    • 3、带头双向循环链表
  • 三、带头双向循环链表的实现
    • 1、结构体定义
    • 2、初始化
    • 3、销毁
    • 4、显示
    • 5、增删查改
  • 四、分析带头双向循环链表
    • 1、存储方式
    • 2、优点
    • 3、缺点
  • 五、总结
    • 1、练习题
    • 2、源代码

一、引言

链表作为数据结构中的重要一员,在众多应用场景中发挥着关键作用。本文旨在深入探讨带头双向循环链表的基本概念、实现机制及其优缺点,以便读者能够更全面地理解并有效运用这一数据结构。


二、链表的基本概念

1、链表是什么

链表是一种线性数据结构,但与传统的顺序表(例如数组)不同,链表中的元素(节点)在内存中并非连续存储。每个节点包含一个数据域和一个或多个指针域,这些指针域指向链表中的其他节点,从而构成链式结构。

2、链表与顺序表的区别

  • 存储方式:顺序表采用连续存储方式,而链表则采用分散存储方式。
  • 访问速度:顺序表支持通过索引直接访问元素,因此访问速度较快;而链表则需要从头节点开始顺序遍历,访问速度相对较慢。
  • 插入与删除操作:顺序表在插入或删除元素时需要移动大量元素,效率较低;链表则通过修改指针指向即可完成插入和删除操作,效率较高。
  • 内存利用率:顺序表在创建时需预先分配连续内存空间,可能导致内存浪费;链表则可根据需求动态分配内存,内存利用率更高。

3、带头双向循环链表

带头双向循环链表是一种特殊的链表结构,具有以下特点:

  • 头节点:通常不存储实际数据,仅作为链表的起始点,便于插入和删除操作。
  • 双向指针:每个节点包含两个指针,一个指向下一个节点,另一个指向上一个节点,从而支持从任意节点向前或向后遍历链表。
  • 循环结构:链表的最后一个节点指向头节点,形成一个环形结构,便于从链表的任意位置开始遍历整个链表。
    这种结构使得带头双向循环链表在插入、删除以及遍历操作上具有更高的灵活性和效率。

请添加图片描述


三、带头双向循环链表的实现

1、结构体定义

在C语言环境中,我们通过定义结构体来构建带头双向循环链表。该结构体融合了数据域与指针域,为链表节点提供了全面的功能支持。以下是一个典型的结构体定义示例:

typedef int DataType;

typedef struct ListNode {
	DataType data;
	struct ListNode* prev;
	struct ListNode* next;
}L;

2、初始化

链表初始化是构建带头双向循环链表的首要步骤。此过程涉及头节点的内存分配、指针的初始化设置,以及环形结构的构建。以下是具体的初始化实现代码:

void Init(L** head)
{
	assert(head != NULL && *head == NULL);

	L* pos = (L*)malloc(sizeof(L));
	if (pos == NULL)
	{
		fprintf(stderr, "内存分配失败");
		exit(EXIT_FAILURE);
	}

	pos->next = pos;
	pos->prev = pos;
	pos->data = 0;
	*head = pos;
}

3、销毁

链表销毁是释放链表所占内存资源的关键步骤。此过程需遍历链表,逐个释放节点的内存,并将头节点指针置为NULL。以下是具体的销毁实现代码:

void Destroy(L** head)
{
	if (head == NULL)
		return;

	L* h = *head;
	while (*head != h)
	{
		L* next = (*head)->next;
		free(*head);
        *head = next;
	}
	*head = NULL;
}

4、显示

链表显示是验证链表正确性的重要手段。此过程通过遍历链表,并打印每个节点的数据部分来实现。以下是具体的显示实现代码:

void Print(L** head, void (*Prin) (DataType))
{
	assert(head != NULL && Prin != NULL);

	printf("head->");
	for (L* i = (*head)->next; i != *head; i = i->next)
	{
		Prin(i->data);
	}
	printf("\n");
}

5、增删查改

void PushFront(L** head, DataType data)
{
	assert(head != NULL && *head != NULL);

	L* pos = (L*)malloc(sizeof(L));
	if (pos == NULL)
	{
		fprintf(stderr, "内存分配失败");
		exit(EXIT_FAILURE);
	}

	pos->next = (*head)->next;
	pos->prev = *head;
	pos->next->prev = pos;
	pos->data = data;
	(*head)->next = pos;
	(*head)->data++;
}

void PopFront(L** head)
{
	assert(head != NULL && *head != NULL && (*head)->next != *head);

	L* next = (*head)->next;
    (*head)->next = next->next;
	next->next->prev = *head;
	free(next);
    (*head)->data--;
}

void PushBack(L** head, DataType data)
{
	assert(head != NULL && *head != NULL);

	L* pos = (L*)malloc(sizeof(L));
	if (pos == NULL)
	{
		fprintf(stderr, "内存分配失败");
		exit(EXIT_FAILURE);
	}

	pos->next = *head;
	pos->prev = (*head)->prev;
	pos->prev->next = pos;
	pos->data = data;
	(*head)->prev = pos;
	(*head)->data++;
}

void PopBack(L** head)
{
	assert(head != NULL && *head != NULL && (*head)->next != *head);

	L* prev = (*head)->prev;
	(*head)->prev = prev->prev;
	prev->prev->next = *head;
	free(prev);
	(*head)->data--;
}

L* Find(L** head, DataType data)
{
	assert(head != NULL && *head != NULL);

	for (L* i = (*head)->next; i != *head; i = i->next)
	{
		if (i->data == data)
			return i;
	}
	return NULL;
}

void Modify(L** head, L* x, DataType data)
{
	assert(head != NULL && *head != NULL && x != NULL);

	for (L* i = (*head)->next; i != *head; i = i->next)
	{
		if (i == x)
		{
			i->data = data;
			return;
		}
	}
	assert(0);
}

四、分析带头双向循环链表

1、存储方式

带头双向循环链表是一种特殊的链表结构,它包含一个头节点,并且该头节点与链表的第一个实际数据节点以及最后一个数据节点之间都通过指针相互连接,形成一个环状结构。每个节点除了存储数据外,还包含两个指针,一个指向前一个节点,另一个指向后一个节点。

2、优点

  • 插入和删除操作效率高:由于链表通过指针连接各个节点,因此在进行插入和删除操作时,只需修改相关节点的指针指向即可,无需移动大量数据。这使得插入和删除操作的时间复杂度为O(1),即常数时间。
  • 内存利用率高:链表结构允许根据实际需求动态分配内存空间,避免了像数组那样因预先分配过大空间而造成的内存浪费。因此,链表在内存利用方面具有较高的灵活性。

3、缺点

  • 访问速度较慢:链表中的数据节点并非连续存储,而是通过指针连接。因此,要访问链表中的某个元素,通常需要从头节点开始遍历链表,直到找到目标节点。这使得访问元素的时间复杂度为O(n),即线性时间,其中n为链表的长度。
  • 存储空间较大:链表中的每个节点除了存储数据外,还需要额外存储两个指针(一个指向前一个节点,另一个指向后一个节点)。这增加了节点的存储空间需求,相对于数组等连续存储结构,链表在存储空间方面可能不够紧凑。

五、总结

1、练习题

  • 移除链表元素
  • 相交链表
  • 环形链表 I
  • 环形链表 II
  • 随机链表的复制

2、源代码

对于无头单向非循环链表的源代码我已经开源在GItee:传送门。


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

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

相关文章

修复PDF打印速度慢

详细问题: 当您尝试将 PDF 文件打印到本地或网络打印机时,打印需要很长时间,因为发送打印作业后,打印机开始打印的速度非常慢,在打印任务中可以看到打印传输的数据在缓慢增长。 从其他程序打印时也不会出现打印速度慢…

c++的web框架Restbed介绍及在嵌入式Linux下的移植详解

随着物联网和嵌入式设备的普及,开发高性能的网络服务变得愈发重要。Restbed是一个用于构建RESTful APIs的轻量级C框架,因其简洁而强大的特性,成为开发者的热门选择。本文将介绍Restbed框架及其在嵌入式Linux平台上的移植方法。 一、Restbed框…

东方博宜 1176. 素数问题

东方博宜 1176. 素数问题 #include<iostream> using namespace std; int main() { int n ;while(cin >> n && n!0) {int count_n ;count_n 0 ;int k ;for( k 1 ; k < n ; k){int count_k ;count_k 0 ;int j ;for( j 2 ; j < k ; j){if (k % j …

基于SSM的大学生勤工助学管理系统(含源码+sql+视频导入教程+文档+PPT)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1 、功能描述 基于SSM的大学生勤工助学管理系统1拥有三种角色&#xff1a;管理员、学生和用工部门&#xff0c;具体功能如下 1.1 背景描述 基于SSM框架&#xff08;SpringSpring MVCMyBatis&#xff09…

Java微信支付接入(1) - API V3 引入支付参数

1.定义微信支付相关参数 wxpay.properties 文件 这个文件定义了之前我们准备的微信支付相关的参数&#xff0c;例如商户号、APPID、API秘钥等等 # 微信支付相关参数 # 商户号 wxpay.mch-id1558950191 # 商户API证书序列号 wxpay.mch-serial-no34345964330B66427E0D3D28826C49…

HTB:Base[WriteUP]

目录 连接至HTB服务器并启动靶机 1.Which two TCP ports are open on the remote host? 2.What is the relative path on the webserver for the login page? 3.How many files are present in the /login directory? 4.What is the file extension of a swap file? …

DeepACO:用于组合优化的神经增强蚂蚁系统解决TSP问题的代码阅读

总体概括 DeepACO与普通ACO不同的是将问题输入实例输入到一个训练的网络中&#xff0c;将网络训练成为一个类似于专家知识的模块&#xff0c;可以生成相应的启发式矩阵网络&#xff0c;从而省去相应的专家知识。 其中在训练网络的代码中&#xff1a; 是进行监督式训练通过trai…

虚幻引擎GAS入门学习笔记(一)

虚幻引擎GAS入门(一) Gameplay Ability System&#xff08;GAS&#xff09; 是一个模块化且强大的框架&#xff0c;用于管理虚幻引擎中的游戏玩法逻辑。它的核心组成部分包括 Gameplay Ability&#xff08;定义和执行能力&#xff09;、Gameplay Effect&#xff08;应用和管理…

数字安全新时代:聚焦关键信息基础设施安全保障——The Open Group 2024生态系统架构·可持续发展年度大会盛大来袭

在全球数字化转型的浪潮中&#xff0c;关键信息基础设施&#xff08;Critical Information Infrastructure&#xff0c;简称CII&#xff09;的安全保障已成为各国政府和企业共同关注的焦点。随着技术的飞速发展和网络威胁的日益复杂&#xff0c;如何构建高效、灵活且安全的数字…

“Flash闪存”基础 及 “SD NAND Flash”产品的测试介绍

目录 一、“FLASH闪存”是什么&#xff1f; 1. 简介 2. 分类 3. 特点 4. 虚拟化 二、SD NAND Flash 1. 概述 2. 特点 3. 引脚分配 4. 数据传输模式 5. SD NAND寄存器 6. 通电图 7. 参考设计 三、STM32测试例程 1. 初始化 2. 单数据块测试 3. 多数据块测试 4.…

SSD | (一)SSD综述

文章目录 &#x1f4da;SSD综述&#x1f407;SSD基本结构&#x1f407;SSD与HDD&#x1f407;SSD基本工作原理⭐SSD请求处理流程⭐SSD主要组成模块⭐SSD读写操作 &#x1f407;SSD产品核心指标⭐基本信息⭐性能指标⭐数据可靠性和寿命⭐功耗 &#x1f4da;可计算存储 &#x1f…

VueRouter前端路由

文章目录 VueRouter前端路由VueRouter 简介安装vuerouter配置router文件子路由路由重定向 VueRouter前端路由 VueRouter 简介 安装vuerouter npm install vue-router4yarn add vue-router4配置router文件 import { createRouter, createWebHistory } from vue-router; impor…

k8s--二进制包部署及常见报错解决方法

部署流程 所有基础流程见此教程&#xff0c;很详细&#xff1a; 从零搭建k8s集群 - 许大仙 - 博客园 (cnblogs.com) 记得在写配置文件时细心点&#xff0c;注意修改自己的ip地址&#xff0c;以及看在哪个主机上操作 这里记得写自己的token 常见报错及解决方法 我只在下边讲…

GDPU Vue前端框架开发 ecmascript6初步使用

前端框架基础&#xff0c;打造你的前端应用。 箭头函数 使用箭头函数实现求多个数的和&#xff0c;可以有一个参数&#xff0c;也可以有多个或零个参数。 let sum (...numbers) > {return numbers.reduce((acc, curr) > acc curr, 0);};let asum(); let bsum(1); let…

实战千问2大模型第五天——VLLM 运行 Qwen2-VL-7B(多模态)

一、简介 VLLM 是一种高效的深度学习推理库&#xff0c;通过PagedAttention算法有效管理大语言模型的注意力内存&#xff0c;其特点包括24倍的吞吐提升和3.5倍的TGI性能&#xff0c;无需修改模型结构&#xff0c;专门设计用于加速大规模语言模型&#xff08;LLM&#xff09;的…

生成对抗网络(GAN,Generative Adversarial Network)

生成对抗网络&#xff08;GAN&#xff0c;Generative Adversarial Network&#xff09;是一种深度学习模型&#xff0c;由两部分组成&#xff1a;生成器&#xff08;Generator&#xff09;和判别器&#xff08;Discriminator&#xff09;。生成器的目标是生成逼真的样本&#x…

Xinstall品牌揭秘:如何成为App拉新的行业翘楚?

在移动互联网时代&#xff0c;App作为连接用户与服务的桥梁&#xff0c;其重要性不言而喻。然而&#xff0c;随着市场竞争的加剧&#xff0c;App拉新&#xff08;即吸引新用户下载并使用App&#xff09;的难度也在逐渐增大。传统的营销方式往往面临着成本高、效率低、用户留存差…

理解PID(零)——什么是PID

PID控制器是一种广泛用于各种工业控制场合的控制器&#xff0c;它结构简单&#xff0c;可以根据工程经验整定参数Kp,Ki,Kd. 虽然现在控制专家提出了很多智能的控制算法&#xff0c;比如神经网络&#xff0c;模糊控制等&#xff0c;但是PID仍然被广泛使用。常见的PID控制器有位置…

视频怎么转gif动图?5个简单转换方法快来学(详细教程)

相信大家在社交平台上会经常看到一些有趣的gif动图表情包&#xff0c;有些小伙伴就会问&#xff1a;这些GIF动图是如何制作的呢&#xff1f;一般GIF动图表情包可以用视频来制作&#xff0c;今天小编就来给大家分享几个视频转成GIF动图的方法&#xff0c;相信通过以下的几个方法…

文献阅读CONCH模型--相关知识点罗列

文章链接&#xff1a;A visual-language foundation model for computational pathology | Nature MedicineThe accelerated adoption of digital pathology and advances in deep learning have enabled the development of robust models for various pathology tasks across…