当前位置: 首页 > article >正文

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

前言

介绍

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

参考

该部分知识参考于《数据结构(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.kler.cn/news/327330.html

相关文章:

  • 鸿蒙开发(NEXT/API 12)【请求用户授权】手机侧应用开发
  • 在Java中使用GeoTools解析POI数据并存储到PostGIS实战
  • 手机如何五开玩梦幻西游端游?用GameViewer远程手机免费畅玩梦幻西游
  • 【大数据】数据中台怎么样助力企业创新和客户实践
  • C++学习,信号处理
  • 组播基础-1
  • 结构体内存对齐与位段
  • 基于 Qwen2.5-0.5B 微调训练 Ner 命名实体识别任务
  • Java数据结构链表(LinkedList详解)
  • Vue3 Typescript 前端页面5min后无操作自动退出至登录页面
  • Windows上面搭建Flutter Android运行环境
  • cmd下的管理员权限闪退 原理分析
  • 【Rockchip系列】官方函数:drm_buf_alloc
  • 【Kotlin基于selenium实现自动化测试】初识selenium以及搭建项目基本骨架(1)
  • 华为OD机试 - 超级玛丽通过吊桥的走法 - 动态规划(Python/JS/C/C++ 2024 E卷 200分)
  • 数据结构——计数、桶、基数排序
  • 深入探索 PyTorch 在机器学习中的应用
  • 观测云对接 SkyWalking 最佳实践
  • Springboot中yml文件不生效原因分析及解决
  • 【C++篇】启航——初识C++(下篇)
  • 滚雪球学Oracle[7.1讲]:Oracle云数据库
  • 如何从 Windows 11/10/8.1/8/7 中恢复已删除的视频
  • 前端导出页面PDF
  • rust的nutyp验证和validator验证数据的方法
  • MySQL | group by 用法
  • 牛客周赛 Round 62
  • 828华为云征文|部署个人文档管理系统 Docspell
  • Kali Linux安全工具
  • 实战OpenCV之形态学操作
  • 网络带宽对于服务器的影响