数据结构——队列的实现

news2024/12/23 18:05:07

在这里插入图片描述

队列,又称为伫列(queue),计算机科学中的一种抽象资料类型,是先进先出(FIFO, First-In-First-Out)的线性表。在具体应用中通常用链表或者数组来实现。队列只允许在后端(称为rear)进行插入操作,在前端(称为front)进行删除操作。
在这里插入图片描述

typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;

这段代码使用 typedef 关键字定义了一个名为 QueueNode 的结构体。QueueNode 结构体包含两个成员:

一个指向另一个 QueueNode 结构体的指针,名为 next,用于表示队列中的下一个节点。
一个名为 data 的变量,其数据类型为 QDataType,用于表示节点中存储的数据。
QNode 被定义为 struct QueueNode* 的别名,也就是说,QNode 是一个指向 QueueNode 结构体的指针。

总的来说,这段代码定义了一个链表节点结构体,可以用来实现队列数据结构,其中每个节点包含一个数据元素和一个指向队列中下一个节点的指针。

typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

这段代码使用 typedef 关键字定义了一个名为 Queue 的结构体。Queue 结构体包含三个成员变量:

一个指向 QNode 结构体的指针,名为 head,用于表示队列中的第一个节点。
一个指向 QNode 结构体的指针,名为 tail,用于表示队列中的最后一个节点。
一个整型变量,名为 size,用于表示队列中节点的数量。
这个结构体可以用来实现一个队列数据结构,其中 head 指向队列的开头,tail 指向队列的结尾,size 记录队列中节点的数量。通常情况下,向队列中添加一个节点会使 tail 指针指向新的节点,从队列中移除一个节点会使 head 指针指向下一个节点,并更新 size 的值。

//初始化队列
void QueueInit(Queue* q)
{
	assert(q);
	q->head = q->tail = NULL;
	q->size = 0;
}

这段代码定义了一个名为 QueueInit 的函数,用于初始化一个队列。函数中传入一个指向 Queue 结构体的指针 q,并使用 assert 宏断言 q 不为 NULL。

函数的实现非常简单,将 q 的 head 和 tail 成员都赋值为 NULL,将 size 成员赋值为 0,这样就完成了队列的初始化操作。由于 q 是一个指针,函数中对其进行的操作实际上是对传入的队列进行修改,因此不需要返回值。

// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->data = data;
	newnode->next = NULL;

	if (q->head == NULL)
	{
		assert(q->tail == NULL);
		q->head = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;

这段代码定义了一个名为 QueuePush 的函数,用于将一个元素插入到队列的尾部。函数中传入一个指向 Queue 结构体的指针 q,以及要插入的数据 data。

函数的实现分为以下几步:

使用 malloc 函数动态分配一个 QNode 结构体大小的内存空间,并将其强制转换为指向 QNode 结构体的指针 newnode。
检查 newnode 是否为空,如果为空则输出错误信息并返回。
将 newnode 的 data 成员赋值为传入的 data,将 newnode 的 next 成员赋值为 NULL,表示 newnode 是队列中的最后一个节点。
检查队列是否为空。如果队列为空,则将队列的 head 和 tail 成员都指向 newnode,表示 newnode 是队列中唯一的节点。
如果队列不为空,则将队列的 tail 节点的 next 指针指向 newnode,表示将 newnode 插入到队列的尾部,并将 tail 指针指向 newnode,表示 newnode 现在是队列中的最后一个节点。
将队列的 size 成员加1,表示队列中节点的数量增加了1。
由于队列是由指针链表实现的,因此在插入节点时需要进行动态内存分配,并将相邻节点的指针进行修改。

// 队头出队列
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->head != NULL);
	QNode* next = q->head->next;
	free(q->head);
	q->head = next;
	if (q->head == NULL)
		q->tail = NULL;
	q->size--;
}

这段代码定义了一个名为 QueuePop 的函数,用于将队列头部的元素弹出队列。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现分为以下几步:

使用 assert 宏检查传入的 q 不为空,以及队列的 head 成员不为 NULL。如果检查失败,则直接返回。
将队列的 head 节点的 next 指针赋值给 next,表示队列头部的下一个节点。
释放队列的 head 节点所占用的内存空间。
将队列的 head 指针指向 next,表示将队列头部的节点弹出队列。
如果队列的 head 成员为 NULL,则将队列的 tail 成员也赋值为 NULL,表示队列已经为空。
将队列的 size 成员减1,表示队列中节点的数量减少了1。
由于队列是由指针链表实现的,因此在弹出节点时需要释放节点的内存空间,并将相邻节点的指针进行修改。

// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->head->data;
}

这段代码定义了一个名为 QueueFront 的函数,用于获取队列头部的元素。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现分为以下几步:

使用 assert 宏检查传入的 q 不为空,以及队列不为空。如果检查失败,则直接返回。
返回队列的 head 节点的 data 成员,即队列头部的元素。
由于队列是由指针链表实现的,因此可以通过访问队列头部节点的 data 成员来获取队列头部的元素。

// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->tail->data;
}

这段代码定义了一个名为 QueueBack 的函数,用于获取队列尾部的元素。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现分为以下几步:

使用 assert 宏检查传入的 q 不为空,以及队列不为空。如果检查失败,则直接返回。
返回队列的 tail 节点的 data 成员,即队列尾部的元素。
由于队列是由指针链表实现的,因此可以通过访问队列尾部节点的 data 成员来获取队列尾部的元素。

// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}

这段代码定义了一个名为 QueueSize 的函数,用于获取队列中有效元素的数量。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现非常简单,直接返回队列的 size 成员,即队列中有效元素的数量。由于 size 成员是在队列的操作过程中动态更新的,因此可以通过该成员来获取队列中有效元素的数量。

// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q)
{
	assert(q);
	return q->size == 0;
}

这段代码定义了一个名为 QueueEmpty 的函数,用于判断队列是否为空。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现非常简单,通过检查队列的 size 成员是否为0来判断队列是否为空。如果 size 等于0,则队列为空,返回 true(非零结果),否则队列非空,返回 false(0)。

// 销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->head = q->tail = NULL;
	q->size = 0;
}

这段代码定义了一个名为 QueueDestroy 的函数,用于销毁一个队列。函数中传入一个指向 Queue 结构体的指针 q。

函数的实现分为以下几步:

使用 assert 宏检查传入的 q 不为空。
将队列的 head 指针赋值给 cur,表示从队列的头部开始销毁节点。
循环遍历队列中的所有节点,每次将 cur 的 next 指针赋值给 next,然后释放 cur 指向的节点所占用的内存空间。
将 cur 指针指向 next,即将指针移动到下一个节点,继续进行循环直到遍历完所有节点。
将队列的 head 和 tail 成员都赋值为 NULL,将队列的 size 成员赋值为 0,表示队列已经被销毁。
由于队列是由指针链表实现的,因此在销毁队列时需要释放每个节点所占用的内存空间,并将指针移动到下一个节点。

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>
typedef int QDataType;
typedef struct QueueNode
{
	struct QueueNode* next;
	QDataType data;
}QNode;
typedef struct Queue
{
	QNode* head;
	QNode* tail;
	int size;
}Queue;

// 初始化队列
void QueueInit(Queue* q);
// 队尾入队列
void QueuePush(Queue* q, QDataType data);
// 队头出队列
void QueuePop(Queue* q);
// 获取队列头部元素
QDataType QueueFront(Queue* q);
// 获取队列队尾元素
QDataType QueueBack(Queue* q);
// 获取队列中有效元素个数
int QueueSize(Queue* q);
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q);
// 销毁队列
void QueueDestroy(Queue* q);

//初始化队列
void QueueInit(Queue* q)
{
	assert(q);
	q->head = q->tail = NULL;
	q->size = 0;
}
// 队尾入队列
void QueuePush(Queue* q, QDataType data)
{
	QNode* newnode = (QNode*)malloc(sizeof(QNode));
	if (newnode == NULL)
	{
		perror("malloc fail");
		return;
	}
	newnode->data = data;
	newnode->next = NULL;

	if (q->head == NULL)
	{
		assert(q->tail == NULL);
		q->head = q->tail = newnode;
	}
	else
	{
		q->tail->next = newnode;
		q->tail = newnode;
	}
	q->size++;

}
// 队头出队列
void QueuePop(Queue* q)
{
	assert(q);
	assert(q->head != NULL);
	QNode* next = q->head->next;
	free(q->head);
	q->head = next;
	if (q->head == NULL)
		q->tail = NULL;
	q->size--;
}
// 获取队列头部元素
QDataType QueueFront(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->head->data;
}
// 获取队列队尾元素
QDataType QueueBack(Queue* q)
{
	assert(q);
	assert(!QueueEmpty(q));
	return q->tail->data;
}
// 获取队列中有效元素个数
int QueueSize(Queue* q)
{
	assert(q);
	return q->size;
}
// 检测队列是否为空,如果为空返回非零结果,如果非空返回0
bool QueueEmpty(Queue* q)
{
	assert(q);
	return q->size == 0;
}
// 销毁队列
void QueueDestroy(Queue* q)
{
	assert(q);
	QNode* cur = q->head;
	while (cur)
	{
		QNode* next = cur->next;
		free(cur);
		cur = next;
	}
	q->head = q->tail = NULL;
	q->size = 0;
}
int main()
{
	Queue q;
	QueueInit(&q);
	QueuePush(&q, 1);
	QueuePush(&q, 2);
	QueuePush(&q, 3);
	QueuePush(&q, 4);
	QueuePush(&q, 5);
	while (!QueueEmpty(&q))
	{
		printf("%d ", QueueFront(&q));
		QueuePop(&q);
	}
	printf("\n");
	
	QueueDestroy(&q);
	return 0;
}
	

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

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

相关文章

Hadoop 集群如何升级?

前言 本文隶属于专栏《大数据技术体系》&#xff0c;该专栏为笔者原创&#xff0c;引用请注明来源&#xff0c;不足和错误之处请在评论区帮忙指出&#xff0c;谢谢&#xff01; 本专栏目录结构和参考文献请见大数据技术体系 正文 升级 Hadoop 集群需要细致的规划&#xff0c;特…

Web安全——JavaScript基础

JavaScript基础 一、概述二、嵌入方法1、内嵌式2、外链式3、行内式 三、语句四、注释五、变量六、JavaScript 保留关键字七、JavaScript 作用域1、JavaScript 局部变量2、JavaScript 全局变量 八、数据类型1、判断类型2、数字类型&#xff08;Number&#xff09;3、字符串型&am…

windows第三大结构体--KPCR

前面我们介绍了windows的两大结构体&#xff0c;一个是进程结构体&#xff0c;一个是线程结构体。那么第三个就是KPCR。KPCR是什么呢&#xff0c;是用于描述CPU的结构体。每一个CPU都有一个这样的结构体来描述CPU干了什么事。 1.在当线程切换的时候&#xff0c;也就是线程从3环…

Windows和Linux动态注入

摘要&#xff1a;最近对动态注入有一些兴趣因此搜索了些资料&#xff0c;简单整理了下相关的技术实现。本文只能够带你理解何如注入以及大概如何实现&#xff0c;对注入的方法描述的并不详细。   关键字&#xff1a;dll注入&#xff0c;hook&#xff0c;提权   读者须知&am…

hadoop -- Yarn资源管理

Yarn YARN被设计用以解决以往架构的需求和缺陷的资源管理和调度软件。 Apache Hadoop YARN &#xff08;Yet Another Resource Negotiator&#xff0c;另一种资源协调者&#xff09;是一种新的 Hadoop 资源管理器&#xff0c;它是一个通用资源管理系统和调度平台&#xff0c;可…

基于uprobe的调试调优浅析

uprobe与krobe对应&#xff0c;动态附加到用户态调用函数的切入点称为uprobe&#xff0c;相比如kprobe 内核函数的稳定性&#xff0c;uprobe 的函数由开发者定义。uprobe是用户态的探针&#xff0c;它和kprobe是相对应的&#xff0c;kprobe是内核态的探针。uprobe需要制定用户态…

深度学习模型压缩方法综述

深度学习因其计算复杂度或参数冗余,在一些场景和设备上限制了相应的模型部署,需要借助模型压缩、系统优化加速等方法突破瓶颈,本文主要介绍模型压缩的各种方法,希望对大家有帮助。 1,模型压缩技术概述 我们知道,一定程度上,网络越深,参数越多,模型也会越复杂,但其最终…

基于Smb协议实现网络文件传输

文章目录 什么是SMB协议SMB与CIFS区别为什么要使用SMB如何对接SMB服务如何用Java实现Smb文件传输SmbV1的实现基于SmbV1的文件上传基于SmbV1的文件下载基于SmbV1的文件重命名基于SmbV1的文件删除基于SmbV1的文件查询 SmbV2的实现基于SmbV2的文件上传基于SmbV2的文件下载基于SmbV…

面向开发人员的 ChatGPT 提示词教程中文版 - ChatGPT 版

面向开发人员的 ChatGPT 提示词教程中文版 - ChatGPT 版 1. 指南1-1. 提示的指南1-2. 配置1-3. 提示语原则原则 1: 写出清晰而具体的指示技巧 1: 使用分隔符来清楚地表明输入的不同部分技巧 2: 要求提供结构化的输出技巧 3: 要求模型检查条件是否得到满足技巧 4: "少许样本…

QML Canvas 元素(绘制文本)

关于 QML Canvas,我们已经学习了如何绘制基本图形、应用样式和颜色、绘制图像等,现在来看一下如何在 Canvas 中绘制文本。 Canvas 提供了两种方式来渲染文本: fillText(text, x, y) 在指定的 (x,y) 位置填充指定的文本 strokeText(text, x, y) 在指定的 (x,y) 位置绘制文本…

基于t分布变异自适应的改进的黏菌算法(TSMA)

目录 一、基于t分布的自适应黏菌优化算法TSAM 1.1 自适应t分布变异 1.2 建立基于t分布的自适应黏菌优化算法TSAM 二、TSMA伪码表示如下&#xff1a; 三、改进对比 黏菌优化算法灵感来自于黏菌的扩张和觅食行为。主要模拟了黏菌在觅食过程中的行为和形态变化&#xff0c;没…

【网络2】MII MDIO

文章目录 1.MII&#xff1a;ISO网络模型中物理层&#xff08;phy&#xff09;和数据链路层&#xff08;mac&#xff09;属于硬件&#xff0c;其余都属于软件kernel2.MDC/MDIO&#xff1a;不仅管phy&#xff0c;只要支持mdio协议都可以管2.1 3.RGMII时序调整&#xff1a;下面波形…

BUUCTF——九连环1

听这个名字就不正常&#xff0c;不会加密九次吧 打开也是一张图片 依旧是存在隐藏文件信息 分离出来后有两个文件&#xff0c;和两个压缩包&#xff0c;但是都需要密码 哦看错了&#xff0c;原来binwalk直接把里面的给分离出来了 所以现在就asd一个文件夹 爆破不出来&#xff0…

为什么调试很重要?gdb调试分析问题

为什么调试很重要&#xff1f; 一、引言二、调试的定义和分类2.1、调试的定义2.2.、调试的分类 三、调试的重要性四、调试的步骤和技巧4.1、定位问题4.2、重现问题4.3、分析问题4.4、解决问题4.5、调试技巧 五、简单的GDB调试示例&#xff1a;六、总结 一、引言 &#x1f4a1; …

【基于Django框架的在线教育平台开发-02】用户注册功能开发

用户注册功能开发 文章目录 用户注册功能开发1 模型层开发2 视图层开发3 配置urls.py4 表单验证5 模板层开发6 效果展示 1 模型层开发 用户数据表如下所示&#xff1a; FieldTypeExtraidintPrime Key & Auto Incrementpasswordvarchar(128)last_logindatetime(6)Allow Nu…

缓存雪崩和缓存穿透的解决方案

缓存雪崩 缓存雪崩是指存储在缓存里面的大量数据&#xff0c;在同一时刻全部过期&#xff0c;大部分流量直接到达了数据库&#xff0c;导致数据库压力增加&#xff0c;造成数据库崩溃的情况。 缓存雪崩的解决方案如下&#xff1a; 每个缓存的key设置不同的过期时间采用多级缓…

STM32单片机(九)USART串口----第四节:USART串口实战练习(串口发送+接收)

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…

在 K8S 中部署一个应用 下

接着上一篇继续部署应用到 K8S中 之前简单部署的简单集群&#xff0c;三个工作节点是运行在 docker 和 kubelet 的&#xff0c;还有一个是控制节点 ReplicationController &#xff0c; pod 和 service 本次关系 之前有提到 ReplicationController &#xff0c; pod 和 服务…

设计模式之命令模式笔记

设计模式之命令模式笔记 说明Command(命令)目录命令模式示例类图订单类厨师类抽象命令类订单命令类服务员类测试类 说明 记录下学习设计模式-命令模式的写法。JDK使用版本为1.8版本。 Command(命令) 意图:将一个请求封装为一个对象&#xff0c;从而使得可以用不同的请求对客…

STM32单片机(九)USART串口----第二节:USART串口外设

❤️ 专栏简介&#xff1a;本专栏记录了从零学习单片机的过程&#xff0c;其中包括51单片机和STM32单片机两部分&#xff1b;建议先学习51单片机&#xff0c;其是STM32等高级单片机的基础&#xff1b;这样再学习STM32时才能融会贯通。 ☀️ 专栏适用人群 &#xff1a;适用于想要…