数据结构——队列的基本操作

news2024/12/23 14:26:19

前言

介绍

 🍃数据结构专区:数据结构

参考

该部分知识参考于《数据结构(C语言版 第2版)》24~28页

🌈每一个清晨,都是世界对你说的最温柔的早安:ૢ(≧▽≦)و✨


目录

前言

1、队列的基本概念

2、基于数组的队列

2.1  宏定义

2.2  数组队列的结构体定义

2.3  队列的初始化

2.4  销毁队列

2.5  求队列长度

2.6  入队

2.7  出队

2.8  获取队头元素

2.9  遍历打印

2.10  整体代码(含测试)

3、基于链表的队列

3.1  宏定义

3.2  链表队列的结构体定义

3.3  队列的初始化

3.4  销毁队列

3.5  求队列中元素个数

3.6  入队

3.7  出队

3.8  获取队头元素

3.9  输出队列元素

3.10  整体代码(含测试)

结语


1、队列的基本概念

队列(Queue)是一种特殊的线性表,它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。这种操作原则使得队列具有先进先出(FIFO, First In First Out)的特性。

  • 基于数组的队列:在这种实现中,队列被限制在一个固定大小的数组中。需要维护两个指针,一个指向队首(front),另一个指向队尾(rear)。当进行入队操作时,如果rear指针指向数组的最后一个位置,且队列未满,可能需要将队列中的元素整体向前移动(或称为“循环”数组),以为新元素腾出空间。
  • 基于链表的队列:在这种实现中,队列由节点组成的链表来表示。每个节点包含数据部分和指向下一个节点的指针。队首和队尾分别由两个指针(head和tail)来维护。这种实现方式更加灵活,因为它不需要预先分配固定大小的存储空间,并且可以在常数时间内完成入队和出队操作。

2、基于数组的队列

2.1  宏定义

#include<iostream>
using namespace std;

//初始化定义
#define OK 1
#define ERROR 0
#define OVERFLOW -1
//Status是函数返回值类型,其值是函数结果状态代码
typedef int Status;

2.2  数组队列的结构体定义

#define MAXQSIZE 100  //队列可能达到的最大长度
typedef int QElemType;
typedef struct
{
	QElemType* base;  //存储空间的基地址
	int front;        //头指针
	int rear;         //尾指针
}SqQueue;

//队空的条件:Q.front == Q.rear
//队满的条件:(Q.rear + 1) % MAXQSIZE == Q.front

2.3  队列的初始化

//队列初始化
Status InitQueue(SqQueue& Q)
{
	//构造一个空队列Q
	Q.base = new QElemType[MAXQSIZE];  //为队列分配一个最大容量为MAXQSIZE的数组空间
  //Q.base = (int*)malloc(MAXQSIZE * sizeof(int));
	if (!Q.base)
		exit(OVERFLOW);      //如果开辟失败就退出程序
	Q.front = Q.rear = 0;    //头尾指针指向0,表示队列为空
	return OK;
}

2.4  销毁队列

// 销毁队列
Status DestroyQueue(SqQueue& Q)
{
	if (Q.base) {
		delete[] Q.base;
		Q.base = NULL;
		Q.front = Q.rear = 0;
	}
	return OK;
}

2.5  求队列长度

//求队列长度
int QueueLength(SqQueue Q)
{
	//返回队列元素个数
	return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}

2.6  入队

//入队
Status EnQueue(SqQueue& Q, QElemType e)
{
	//插入元素e为Q的新的队尾元素
	if ((Q.rear + 1) % MAXQSIZE == Q.front)
		return ERROR;    //若尾指针在循环意义上加1后等于头指针,表明队满
	Q.base[Q.rear] = e;     //新元素插入队尾
	Q.rear = (Q.rear + 1) % MAXQSIZE;     //队尾指针加1
	return OK;
}

2.7  出队

//出队
Status DeQueue(SqQueue& Q, QElemType& e)
{
	//删除队头元素,用e返回其值
	if (Q.front == Q.rear)
		return ERROR;  //队空
	e = Q.base[Q.front];
	Q.front = (Q.front + 1) % MAXQSIZE;
	return OK;
}

2.8  获取队头元素

//取队头元素
QElemType GetHead(SqQueue Q)
{
	//返回队头元素,不改变头指针
	if (Q.front != Q.rear)  //队列非空
		return Q.base[Q.front];
}

2.9  遍历打印

//输出队列元素
void PrintQueue(SqQueue& Q)
{
	printf("(front) ");
	int i;
	for (i = Q.front; i != Q.rear; i++)
	{
		printf("%d ", Q.base[i]);
	}
	printf("(rear)\n");
}

2.10  整体代码(含测试)

#include<iostream>
using namespace std;

//初始化定义
#define OK 1
#define ERROR 0
#define OVERFLOW -1
//Status是函数返回值类型,其值是函数结果状态代码
typedef int Status;

#define MAXQSIZE 100  //队列可能达到的最大长度
typedef int QElemType;
typedef struct
{
	QElemType* base;  //存储空间的基地址
	int front;        //头指针
	int rear;         //尾指针
}SqQueue;

//队空的条件:Q.front == Q.rear
//队满的条件:(Q.rear + 1) % MAXQSIZE == Q.front

//队列初始化
Status InitQueue(SqQueue& Q)
{
	//构造一个空队列Q
	Q.base = new QElemType[MAXQSIZE];  //为队列分配一个最大容量为MAXQSIZE的数组空间
  //Q.base = (int*)malloc(MAXQSIZE * sizeof(int));
	if (!Q.base)
		exit(OVERFLOW);      //如果开辟失败就退出程序
	Q.front = Q.rear = 0;    //头尾指针指向0,表示队列为空
	return OK;
}

// 销毁队列
Status DestroyQueue(SqQueue& Q)
{
	if (Q.base) {
		delete[] Q.base;
		Q.base = NULL;
		Q.front = Q.rear = 0;
	}
	return OK;
}

//求队列长度
int QueueLength(SqQueue Q)
{
	//返回队列元素个数
	return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}

//入队
Status EnQueue(SqQueue& Q, QElemType e)
{
	//插入元素e为Q的新的队尾元素
	if ((Q.rear + 1) % MAXQSIZE == Q.front)
		return ERROR;    //若尾指针在循环意义上加1后等于头指针,表明队满
	Q.base[Q.rear] = e;     //新元素插入队尾
	Q.rear = (Q.rear + 1) % MAXQSIZE;     //队尾指针加1
	return OK;
}

//出队
Status DeQueue(SqQueue& Q, QElemType& e)
{
	//删除队头元素,用e返回其值
	if (Q.front == Q.rear)
		return ERROR;  //队空
	e = Q.base[Q.front];
	Q.front = (Q.front + 1) % MAXQSIZE;
	return OK;
}

//取队头元素
QElemType GetHead(SqQueue Q)
{
	//返回队头元素,不改变头指针
	if (Q.front != Q.rear)  //队列非空
		return Q.base[Q.front];
}

//输出队列元素
void PrintQueue(SqQueue& Q)
{
	printf("(front) ");
	int i;
	for (i = Q.front; i != Q.rear; i++)
	{
		printf("%d ", Q.base[i]);
	}
	printf("(rear)\n");
}

int main()
{
	SqQueue Q;
	QElemType e;

	cout << "初始化队列..." << endl;
	if (InitQueue(Q) == OK)
		cout << "队列初始化成功!" << endl;
	else
		cout << "队列初始化失败!" << endl;

	cout << "\n测试入队操作:" << endl;
	for (int i = 1; i <= 5; i++)
	{
		if (EnQueue(Q, i) == OK)
			cout << i << " 入队成功" << endl;
		else
			cout << i << " 入队失败" << endl;
	}

	cout << "\n当前队列:" << endl;
	PrintQueue(Q);

	cout << "\n队列长度:" << QueueLength(Q) << endl;

	cout << "\n测试出队操作:" << endl;
	for (int i = 0; i < 3; i++)
	{
		if (DeQueue(Q, e) == OK)
			cout << e << " 出队成功" << endl;
		else
			cout << "出队失败,队列可能为空" << endl;
	}

	cout << "\n当前队列:" << endl;
	PrintQueue(Q);

	cout << "\n队列长度:" << QueueLength(Q) << endl;

	cout << "\n队头元素:" << GetHead(Q) << endl;

	cout << "\n销毁队列..." << endl;
	if (DestroyQueue(Q) == OK)
		cout << "队列销毁成功!" << endl;
	else
		cout << "队列销毁失败!" << endl;

	return 0;
}

3、基于链表的队列

3.1  宏定义

//链队列的实现
#include<iostream>
using namespace std;

//初始化定义
#define OK 1
#define ERROR 0
#define OVERFLOW -1
//Status是函数返回值类型,其值是函数结果状态代码
typedef int Status;

3.2  链表队列的结构体定义

typedef int QElemType;
typedef struct QNode
{
	QElemType data;
	struct QNode* next;
}QNode, *QueuePtr;

typedef struct
{
	QueuePtr front;   //队头指针
	QueuePtr rear;    //队尾指针
}LinkQueue;

3.3  队列的初始化

//队列初始化
Status InitQueue(LinkQueue& Q)
{
	//构造一个空队列
	Q.front = Q.rear = new QNode;  //生成新结点作为头结点,队头和队尾指针指向此结点
	Q.front->next = NULL;   //头结点的指针域置空
	return OK;
}

3.4  销毁队列

//销毁队列
Status DestroyQueue(LinkQueue& Q)
{
	while (Q.front)
	{
		Q.rear = Q.front->next;
		delete Q.front;
		Q.front = Q.rear;
	}
	return OK;
}

3.5  求队列中元素个数

//求队列中元素数量
int QueueLength(LinkQueue Q)
{
	int count = 0;
	QNode* p = Q.front->next;
	while (p)
	{
		count++;
		p = p->next;
	}
	return count;
}

3.6  入队

//入队
Status EnQueue(LinkQueue& Q, QElemType e)
{
	//插入元素e为Q的新的队尾元素
	QNode* p = new QNode;
	p->data = e;
	p->next = NULL;
	Q.rear->next = p;   //将新结点插入队尾
	Q.rear = p;         //修改队尾指针
	return OK;
}

3.7  出队

//出队
Status DeQueue(LinkQueue& Q, QElemType& e)
{
	//删除队头元素,用e返回其值
	if (Q.front == Q.rear)
		return ERROR;   //若队列为空,返回ERROR
	QNode* p = Q.front->next;
	e = p->data;  //用e保存头结点数据
	Q.front->next = p->next;  //修改头结点指针域
	if (Q.rear == p)
		Q.rear = Q.front;  //最后一个元素被删除,队尾指针指向头结点
	delete p;   //释放原队头元素的空间
	return OK;
}

3.8  获取队头元素

//取队头元素
QElemType GetHead(LinkQueue Q)
{
	//返回Q的队头元素,不修改头指针
	if (Q.front != Q.rear)
		return Q.front->next->data;  //返回头元素的值,队头元素不变
}

3.9  输出队列元素

//输出队列元素
void PrintQueue(LinkQueue Q)
{
	//前提队列不为空
	printf("(front) ");
	if (Q.front != Q.rear)
	{
		QNode* p = Q.front->next;
		while (p != NULL)
		{
			printf("%d ", p->data);
			p = p->next;
		}
	}
	printf("(rear)\n");
}

3.10  整体代码(含测试)

//链队列的实现
#include<iostream>
using namespace std;

//初始化定义
#define OK 1
#define ERROR 0
#define OVERFLOW -1
//Status是函数返回值类型,其值是函数结果状态代码
typedef int Status;

typedef int QElemType;
typedef struct QNode
{
	QElemType data;
	struct QNode* next;
}QNode, *QueuePtr;

typedef struct
{
	QueuePtr front;   //队头指针
	QueuePtr rear;    //队尾指针
}LinkQueue;

//队列初始化
Status InitQueue(LinkQueue& Q)
{
	//构造一个空队列
	Q.front = Q.rear = new QNode;  //生成新结点作为头结点,队头和队尾指针指向此结点
	Q.front->next = NULL;   //头结点的指针域置空
	return OK;
}

//销毁队列
Status DestroyQueue(LinkQueue& Q)
{
	while (Q.front)
	{
		Q.rear = Q.front->next;
		delete Q.front;
		Q.front = Q.rear;
	}
	return OK;
}

//求队列中元素数量
int QueueLength(LinkQueue Q)
{
	int count = 0;
	QNode* p = Q.front->next;
	while (p)
	{
		count++;
		p = p->next;
	}
	return count;
}

//入队
Status EnQueue(LinkQueue& Q, QElemType e)
{
	//插入元素e为Q的新的队尾元素
	QNode* p = new QNode;
	p->data = e;
	p->next = NULL;
	Q.rear->next = p;   //将新结点插入队尾
	Q.rear = p;         //修改队尾指针
	return OK;
}

//出队
Status DeQueue(LinkQueue& Q, QElemType& e)
{
	//删除队头元素,用e返回其值
	if (Q.front == Q.rear)
		return ERROR;   //若队列为空,返回ERROR
	QNode* p = Q.front->next;
	e = p->data;  //用e保存头结点数据
	Q.front->next = p->next;  //修改头结点指针域
	if (Q.rear == p)
		Q.rear = Q.front;  //最后一个元素被删除,队尾指针指向头结点
	delete p;   //释放原队头元素的空间
	return OK;
}

//取队头元素
QElemType GetHead(LinkQueue Q)
{
	//返回Q的队头元素,不修改头指针
	if (Q.front != Q.rear)
		return Q.front->next->data;  //返回头元素的值,队头元素不变
}

//输出队列元素
void PrintQueue(LinkQueue Q)
{
	//前提队列不为空
	printf("(front) ");
	if (Q.front != Q.rear)
	{
		QNode* p = Q.front->next;
		while (p != NULL)
		{
			printf("%d ", p->data);
			p = p->next;
		}
	}
	printf("(rear)\n");
}

int main()
{
	LinkQueue Q;
	QElemType e;

	cout << "初始化队列..." << endl;
	if (InitQueue(Q) == OK)
		cout << "队列初始化成功!" << endl;
	else
		cout << "队列初始化失败!" << endl;

	cout << "\n测试入队操作:" << endl;
	for (int i = 1; i <= 5; i++)
	{
		if (EnQueue(Q, i) == OK)
			cout << i << " 入队成功" << endl;
		else
			cout << i << " 入队失败" << endl;
	}

	cout << "\n当前队列:" << endl;
	PrintQueue(Q);

	cout << "\n队列长度:" << QueueLength(Q) << endl;

	cout << "\n测试出队操作:" << endl;
	for (int i = 0; i < 3; i++)
	{
		if (DeQueue(Q, e) == OK)
			cout << e << " 出队成功" << endl;
		else
			cout << "出队失败,队列可能为空" << endl;
	}

	cout << "\n当前队列:" << endl;
	PrintQueue(Q);

	cout << "\n队列长度:" << QueueLength(Q) << endl;

	cout << "\n队头元素:" << GetHead(Q) << endl;

	cout << "\n销毁队列..." << endl;
	if (DestroyQueue(Q) == OK)
		cout << "队列销毁成功!" << endl;
	else
		cout << "队列销毁失败!" << endl;

	return 0;
}

结语

到此我们队列的基本操作也就完成了,那么我们对于数据结构中的顺序表、栈、队列的学习已经基本完成,可以进行一些简单的力扣题的书写了,这里并没有太大的难度,需要的是不断去熟悉和练习来完成对这部分知识的掌握!

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

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

相关文章

Flutter 3.24 AAPT: error: resource android:attr/lStar not found.

在Android build,gradle下面&#xff0c;添加右边红框的代码&#xff1a; subprojects {afterEvaluate { project ->if (project.plugins.hasPlugin("com.android.application") ||project.plugins.hasPlugin("com.android.library")) {project.androi…

复写零——双指针算法

题目链接 复写零https://leetcode.cn/problems/duplicate-zeros/description/ 题目要求 样例 题目分析 先看示例1&#xff0c;题目要求将数组中所有的0&#xff0c;均复写一遍&#xff0c;且要在原数组上进行更改&#xff0c;多余的元素消失 但我们发现&#xff0c;如果双指针…

04DSP学习-利用syscfg配置EPWM

打开syscfg文件&#xff0c;左侧control栏中找到EPWM&#xff0c;点击&#xff0c;发现TI提供了一些帮助文档&#xff0c;帮助了解如何使用syscfg以及如何了解EPWM。我们结合配置过程去理解如何使用。 设计目标 使用EPWM1&#xff1b;增减计数&#xff1b;PWM频率为10kHz&…

ios内购支付-支付宝APP支付提现

文章目录 前言一、IOS内购支付&#xff08;ios订单生成自己写逻辑即可&#xff09;1.支付回调票据校验controller1.支付回调票据校验server 二、安卓APP支付宝支付1.生成订单返回支付宝字符串&#xff08;用于app拉起支付宝&#xff0c;这里用的是证书模式&#xff09;2.生成订…

相机基础概念

景深&#xff1a; 景深的定义 DOF:depth of filed 是指在摄影机镜头或其他成像器前沿能够取得清晰图像的成像所测定的被摄物体前后距离范围。光圈、镜头、及焦平面到拍摄物的距离是影响景深的重要因素。定义3&#xff1a;在镜头前方&#xff08;焦点的前、后&#xff09;有一…

PCL 投影滤波器

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 投影滤波 2.1.2 可视化 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xff08;长期更新&#xff09; 一、…

Java的栈帧和动态链接是什么?

在 Java 的面试过程中&#xff0c;不可避免的一个面试题那就是 JVM&#xff0c;而 JVM 的面试题中&#xff0c;有各种&#xff0c;比如在堆中会被问到的关于垃圾回收机制的相关问题&#xff0c;在栈中会被问到入栈以及出栈的过程&#xff0c;来聊一下关于栈的相关问题&#xff…

【EchoMimic整合包及教程】蚂蚁集团支付宝开源了数字人技术EchoMimic,可用于虚拟主播、视频编辑等

蚂蚁集团支付宝开源了数字人技术EchoMimic&#xff0c;可用于虚拟主播和视频编辑。EchoMimic是一个音频驱动的肖像动画生成工具&#xff0c;具有丰富的表情和流畅的动作。它支持音频驱动、姿势驱动和音频与姿势混合驱动动画&#xff0c;并提供了易于使用的WebUI和GradioUI界面。…

三品PLM系统如何提升企业产品研发效率?

三品PLM系统如何提升企业研发效率 在竞争日益激烈的市场环境中&#xff0c;企业研发效率的高低直接决定了其产品的上市速度、质量以及市场竞争力。为了应对这一挑战&#xff0c;越来越多的企业开始引入PLM系统&#xff0c;而三品PLM系统凭借其强大的功能和全面的解决方案&…

移动技术开发:音乐播放器

1 实验名称 音乐播放器 2 实验目的 掌握使用Service启动服务的方法&#xff0c;掌握BroadcastReceiver广播传递机制的实现&#xff0c;利用Activity、Service和BroadcastReceiver实现一个音乐播放器APP。 3 实验源代码 布局文件代码&#xff1a; <?xml version"1.…

yum无法使用解决办法

yum无法使用解决方法&#xff08;比较全&#xff0c;以后如果遇到别的问题还会添加&#xff09;yum无法使用解决方法&#xff08;比较全&#xff0c;以后如果遇到别的问题还会添加&#xff09; 如下&#xff0c;新装的linux虚拟机&#xff0c;yum安装wget报错 Cannot find a …

内存占用估算方法

优质博文&#xff1a;IT-BLOG-CN 通过掌握每种数据类型的大小&#xff0c;就可以更准确地预测对象和数据的内存消耗。 一、基础数据类型 Java基础数据类型结构&#xff0c;在64位系统开启指针压缩情况下的内存占用字节数&#xff1a; booleanbytecharshortintlongfloatdoub…

D23【 python 接口自动化学习】- python 基础之判断与循环

day23 match语句 学习日期&#xff1a;20240930 学习目标&#xff1a;判断与循环 --33 match语句&#xff1a;如何通过match关键字来处理程序的分支逻辑&#xff1f; 学习笔记&#xff1a; match语句的语法 基本写法 代码实现&#xff08;后续更新为自己写的代码&#xff…

软件测试学习笔记丨Mock的价值与实战

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/32331 一、Mock的价值与意义 1.1 简介 测试过程中&#xff0c;对于一些不容易构造或获取的对象&#xff0c;用一个虚拟的对象来替代它&#xff0c;达到相同的效果&#xff0c;这个虚拟的对象…

YOLOv11尝鲜测试五分钟极简配置

ultralytics团队在最近又推出了YOLOv11&#xff0c;不知道在有生之年能不能看到YOLOv100呢哈哈。 根据官方文档&#xff0c;在 Python>3.8并且PyTorch>1.8的环境下即可安装YOLOv11&#xff0c;因此之前YOLOv8的环境是可以直接用的。 安装YOLOv11&#xff1a; pip instal…

安宝特分享 | AR技术重塑工业:数字孪生与沉浸式培训的创新应用

在数字化转型的浪潮中&#xff0c;AR&#xff08;增强现实&#xff09;技术与工业的结合正在呈现新的趋势和应用延伸。特别是“数字孪生”概念的崛起&#xff0c;为AR技术在工业中提供了独特而创新的切入点。 本文将探索AR如何与数字孪生、沉浸式体验和实用案例相结合&#xf…

OpenHarmony(鸿蒙南向开发)——小型系统芯片移植指南(一)

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 移植须知 本文详细介绍如何将OpenHarmony小型系统的linux和LiteOS…

Elasticsearch学习笔记(3)

RestAPI Elasticsearch&#xff08;ES&#xff09;官方提供了多种语言的客户端库&#xff0c;用于与Elasticsearch进行交互。这些客户端库的主要功能是帮助开发者更方便地构建和发送DSL&#xff08;Domain Specific Language&#xff09;查询语句&#xff0c;并通过HTTP请求与…

全面提升MySQL性能:从硬件到配置再到代码的最佳实践

MySQL 是全球最流行的开源关系型数据库管理系统之一&#xff0c;广泛应用于各种规模的应用程序中。随着应用规模的增长&#xff0c;数据库的性能优化成为提升系统整体性能的关键因素。本文将从多个角度探讨如何对MySQL进行性能优化&#xff0c;帮助开发者和DBA解决实际问题&…

JWT 令牌生成报错

一、问题描述 我在获取JWT令牌时&#xff0c;报了一个这样的错误 error&#xff1a;io.jsonwebtoken.security.WeakKeyException: The signing keys size is 64 bits which is not secure enough for the HS256 algorithm. 二、问题原因 原因是我这里指定的签名密钥也就是si…