3.2 队列

news2024/12/24 8:48:58

        定义: 队列是一种插入元素只能在一端进行, 删除元素只能在另一端进行的线性表. 所谓队列是线性表, 是指队列的逻辑结构属于线性表, 只不过在操作上加了一些约束. 队列可以插入元素的一端叫做队尾(Rear), 可以删除元素的一端叫做队头(Front). 队列是一种先进先出的结构. First In, First Out (FIFO). 

图1. 元素入队和出队

1. 顺序队列(循环队列)

 图2. 元素入队

 图3. 元素出队

        如图, front指针指向队列首个元素的前一个位置, rear指向队列的最后一个元素. front和rear的初始值均为0. 关于入队和出队操作以及判断队空, 可以这样规定: 

        入队: 先移动队尾指针, 再入队元素; 即rear++; queue[ rear ] = x; 

        出队: 先移动队头指针, 再出队元素; 即front++; x = queue[ front ]; 元素出队后它的值还是残留在数组中的, 但已不属于队列. 

        队空: rear == front; 

        需要注意的是, 这只是一种规定, 在不同的规定下入队和出队及判断队空可能会有所不同. 

 图4. 假溢出

        如图, rear再向后移动会造成数组越界, 但是数组内确实有空位置存在, 这种情况称为假溢出

 图5. 假溢出解决方法

        注意, 上图只是一种演示方法, 实际上在内存中数组是不会被"掰弯"的. 

        如图, 定义队列queue[MAX_SIZE], front和rear初始值均为0.

        入队时, 仍是先移动指针rear, 与之前不同的是, 当rear越界时, 需要让rear折返回数组的起始位置, 即rear = ( rear + 1 ) % MAX_SIZE; 然后入队元素, 即queue[ rear ] = x; 

        出队时, 仍时先移动指针front, 与之前不同的是, 当front越界时, 需要让front折返回数组的起始位置, 即front = ( front + 1 ) % MAX_SIZE; 然后出队元素, 即x = queue[ front ]; 

        队空: front == rear 为真; 

        队满: front == ( rear + 1 ) % MAX_SIZE为真; 

#include <iostream>

const int MAX_SIZE = 10;

/// <summary>
/// 队列结构体定义
/// </summary>
typedef struct {
	int data[MAX_SIZE];
	int front, rear;
}SqQueue;

/// <summary>
/// 初始化队列
/// </summary>
/// <param name="Q"></param>
void InitQueue(SqQueue& Q) {
	Q.front = 0;
	Q.rear = 0;
}

/// <summary>
/// 元素入队
/// </summary>
/// <param name="Q"></param>
/// <param name="x">入队元素</param>
void EnQueue(SqQueue& Q, int x) {
	Q.rear = (Q.rear + 1) % MAX_SIZE;
	Q.data[Q.rear] = x;
}

/// <summary>
/// 元素出队
/// </summary>
/// <param name="Q"></param>
/// <param name="x"></param>
void DeQueue(SqQueue& Q, int &x) {
	Q.front = (Q.front + 1) % MAX_SIZE;
	x = Q.data[Q.front];
}

/// <summary>
/// 判断队空, 若队空返回true, 否则返回false
/// </summary>
/// <param name="Q"></param>
/// <returns></returns>
bool QueueEmpty(SqQueue Q) {
	if (Q.front == Q.rear) {
		return true;
	}
	return false;
}

/// <summary>
/// 判断队满, 若队满返回true, 否则返回false
/// </summary>
/// <param name="Q"></param>
/// <returns></returns>
bool QueueFull(SqQueue Q) {
	if (Q.front == (Q.rear + 1) % MAX_SIZE) {
		return true;
	}
	return false;
}

int main()
{
	SqQueue Q;
	InitQueue(Q);
	int i = 0;
	while (!QueueFull(Q))
	{
		printf("入栈元素: %d\n", i);
		EnQueue(Q, i);
		i++;
	}
	printf("---------------------------\n");
	while (!QueueEmpty(Q))
	{
		int x;
		DeQueue(Q, x);
		printf("出栈元素: %d\n", x);
	}
}


代码1: 顺序队列的基本操作

        运行结果如下: 

 图6. 运行结果

        可以看出容量为10的数组在队满时只容纳了9个元素. 有一个位置没有容纳元素. 

2. 链式队列

 图7. 链式队列

        如图, front指向链式队列的头结点, rear指向链式队列的尾结点. 

        入队: p指向入队结点, 注意是从队尾入队. p->next = rear->next; rear->next = p; rear = p; 

        出队: p指向出队结点, 注意是从队头出队. p = front->next; front->next = p->next; x = p->data; free(p); 

        队空: front->next == NULL为真; 

        队满: 假设内存足够大, 不考虑内存满的情况. 

        很多考题里将front和rear包在一个结构体变量里. 

 图8. 将front和rear包在一个结构体变量里

        图中的队列没有头结点, front指向队列首个元素, 当front == NULL时, 队列为空. 为了统一操作, 我们在代码实现时设计成带头结点的单链表. 则front指向头结点, front==rear时, 队列为空. 

#include <iostream>

/// <summary>
/// 链式队列结点结构体
/// </summary>
typedef struct LNode {
	int data;
	struct LNode* next;
}LNode;

/// <summary>
/// 链式队列
/// </summary>
typedef struct {
	struct LNode* front;
	struct LNode* rear;
}LinkQueue;

/// <summary>
/// 初始化队列
/// </summary>
/// <param name="Q"></param>
void InitQueue(LinkQueue& Q) {
	LNode* H = (LNode*)malloc(sizeof(LNode));
	H->data = NULL;
	H->next = NULL;

	Q.front = H;
	Q.rear = H;
}

/// <summary>
/// 入队
/// </summary>
/// <param name="Q"></param>
/// <param name="x">入队元素</param>
void EnQueue(LinkQueue& Q, int x) {
	LNode* p = (LNode*)malloc(sizeof(LNode));
	p->data = x;
	p->next = NULL;

	//下面这个if()语句是不必要的, 因为Q.rear->next = p;这句代码会设置Q.front.next为p, 当然写出来也不会错
	//if (Q.front == Q.rear) {	//若入队前队列为空, 则先设置Q.front.next为首个入队元素
	//	Q.front->next = p;
	//}

	p->next = Q.rear->next;
	Q.rear->next = p;		//若入队前队列为空, 这一句会设置Q.front.next为p, 
							//因为队列为空时, Q.front == Q.rear == H
	Q.rear = p;				//这里改变了Q.rear的指向的元素, 故再次入队时, 
							//Q.rear->next = p;不会再改变Q.front的next的值, 
							//也即Q.front.next始终指向了队列首个元素

	//free(p);		注意这里不能释放p所指结点的内存空间
}

/// <summary>
/// 出队
/// </summary>
/// <param name="Q"></param>
/// <param name="x">出队元素</param>
void DeQueue(LinkQueue& Q, int& x) {
	LNode* p = Q.front->next;

	x = p->data;

	Q.front->next = p->next;

	if (Q.rear == p) {
		Q.rear = Q.front;		//若原队列只有一个结点, 删除后变空
	}

	free(p);
}

/// <summary>
/// 判断队空, 队空返回true, 队不空返回false
/// </summary>
/// <param name="Q"></param>
/// <returns></returns>
bool QueueEmpty(LinkQueue Q) {
	if (Q.front == Q.rear) {
		return true;
	}
	return false;
}

int main()
{
	LinkQueue Q;
	InitQueue(Q);

	int i = 1;
	while (i < 10) {
		printf("入队元素: %d\n", i);
		EnQueue(Q, i);
		i++;
	}
	printf("-----------------------------\n");

	while (!QueueEmpty(Q))
	{
		int x;
		DeQueue(Q, x);
		printf("出队元素: %d\n", x);
	}
}


代码2: 链式队列的基本操作

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

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

相关文章

vue创建脚手架项目启动

vue创建脚手架项目&启动 1、创建项目2、运行项目 1、创建项目 vue create vuecli-demo说明这里使用vue2项目 2、运行项目 cd vuecli-demo yarn serve访问 http://localhost:8080/

springboot()—— 集成redis

1、新建一个springboot项目 2、添加redis依赖包 可以在新建项目的时候就选上 也可以建完项目以后手动导入pom.xml <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId> </d…

[uni-app] 微信小程序 - 组件找不到/导入报错 (分包问题导致)

文章目录 问题表现问题原因 问题表现 切换了个路径下的组件, 导入失败, 尝试了清缓存\重启\删项目等一些列操作均无效 上面两个路径中, 都存在一模一样的videItem.vue Main路径是可以导入的 Main路径是无法导入的 问题原因 后来发现, 是 分包的问题导致. 我们先来假设一个场…

如何通过日志分析性能

根据监控指标&#xff0c;只要有一项指标不超了&#xff0c;就不满足性能&#xff0c;根据这个指标&#xff0c;分析数据流向&#xff0c;看下到底什么原因导致这个指标超了&#xff0c;是本身原因还是其它原因&#xff0c;分析客户端、网络、硬件、中间件、数据库、应用程序等…

一个简单的 Android 版本目录(Version catalog)实现指南

一个简单的 Android 版本目录实现指南 使用 TOML 格式 在本文中&#xff0c;我们将探讨版本目录以及如何实现它。 版本目录 Gradle 版本目录使您能够以可扩展的方式添加和维护依赖项和插件。因此&#xff0c;不必在各个构建文件中硬编码依赖项名称和版本&#xff0c;而是在目…

Windows 10 关于进程出现 已挂起,导致无法结束任务,或者taskkill 命令也被拒绝访问等问题解决方法

理解 也就是说&#xff0c;平时电脑启动的是快速启动配置&#xff0c;相当于是休眠&#xff0c;但是有可能会存在一些 bug &#xff0c;所以&#xff0c;作为开发者来说&#xff0c;最好是取消这个快速启动的配置&#xff0c;不然 bug 满天飞&#xff0c;当然这只是有可能。 …

MYSQL练习三答案

练习3 构建数据库 数据库 数据表 answer开头表为对应题号答案形成的数据表 表结构 表数据 答案 1、写一条SQL查询语句&#xff0c;找出所有属于"Electronics"类 别的产品信息。 SQL语句 select * from products where category Electronics;结果&#xff1a; 2…

安防视频管理平台GB设备接入EasyCVR, 如何获取RTMP与RTSP视频流

安防视频监控平台EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安防视频监控的能力&#xff0c;比…

微信小程序中使用echarts方法

小程序中使用echarts echarts是一个基于JS的数据可视化图标库&#xff0c;它提供了直观&#xff0c;生动&#xff0c;可交互&#xff0c;可个性定制的数据可视化图表。一般在vue中会使用到&#xff0c;并且官网也详细的说明了如何在vue中使用&#xff0c;但是今天我想来探讨的…

python面试宝典1

目录标题 python基础1、代码中修改不可变数据会出现什么问题&#xff1f;什么异常&#xff1f;2、a1,b2,不用中间变量交换 a 和 b 的值&#xff1f;3、print调用python中底层的什么方法&#xff1f;4、理解下面代码&#xff0c;结果输出5、对input()函数的理解6、理解代码&…

誉天程序员-常用网站

学习方法六大招 日常你是如何学习新知识的&#xff1f;&#xff08;面试官爱问哦&#xff09; 1、百度百科概念了解 2、技术官网简单了解 3、同类产品技术选型 4、百度搜索入门案例 5、泛读百文瘦弱圆润 6、遇到问题问AI助手&#xff08;chatGPT&#xff09;噢 技术路线图&a…

C#中未能找到为main方法指定的XXX.Program怎么解决

有时在修改项目名称后&#xff0c;报错未能找到为main方法指定的XXX.Program 解决办法&#xff1a; 点击进入项目属性&#xff0c;将启动对象设置为空或者你要指定的XXX.Program&#xff08;改名后的&#xff09;

基于SDRAM的串口回环测试

文章目录 前言一、SDRAM简介二、SDRAM芯片手册解析2.1 芯片信息2.2 功能描述2.3 指令集 三、SDRAM配置3.1 初始化3.2 自动刷新3.3 突发写操作3.4 突发读操作3.5 仲裁3.5 FIFO控制3.5 FIFO数据读 四、结果验证 前言 本文将介绍在AWC_C4MB开发板上进行基于串口的SDRAM数据回环测试…

能直接运营的校园跑腿代买拿寄取小程序开发

​说到做跑腿生意&#xff0c;除了做同城跑腿配送外&#xff0c;校园跑腿可是即成本又低又好操作的一个项目。 一般省会城市大学大专基本都是有好几所的&#xff0c;学校的特点是人员密集&#xff0c;跑腿配送周期短&#xff0c;且配送人员好招募&#xff0c;推广人员好招募。…

css - Media Query

使用bootstrap的grid system可以在一个较为粗糙的范围得到较好的响应性&#xff0c;但是通过viewport可以看到网站在具体哪个像素点处变得丑陋&#xff0c;再通过css media query来精细调整网页布局。 可以通过media query来提高网页移动响应能力。

网络安全 Day17-计算机网络知识02(复杂物理原件)

计算机网络知识02&#xff08;复杂物理原件&#xff09; 1. 交换机2. 路由器 1. 交换机 什么是交换机 实现一个网络内多台主机之间通讯的设备用于电信号转发和放大的网络设备 常见的交换机&#xff1a;以太网交换机&#xff0c;电话交换&#xff0c;光纤交换机交换机的种类 二…

MySQL基础(三十一)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、概述 1. 什么是数据库 2. 数据库能干什么 2.1 企业应用 2.2 金融行业 2.3 电子商务 2.4 社交媒体 2.5 物联网 3. 为什么要用数据库&#xff0c;优势、特性&…

C#常见技能_参数传递

大家好&#xff0c;我是华山自控编程朱老师 前几天一个学员在学习C#与参数传递交互时,也不知道参数传递可以用来做什么 。下面我们就详细讲讲C# 和参数传递交互的相关知识。 C#是一种面向对象的编程语言&#xff0c;支持多种参数传递方式&#xff0c;包括传值和传引用两种方式…

Ubuntu18.04 下配置Clion

配置Clion 安装gcc、g、make Ubuntu中用到的编译工具是gcc©&#xff0c;g&#xff08;C&#xff09;&#xff0c;make(连接)。因此只需安装对应的工具包即可。Ubuntu下使用命令安装这些包&#xff1a; &#xff08;1&#xff09;安装gcc sudo apt install gcc&am…

Mysql错误日志、通用查询日志、二进制日志和慢日志的介绍和查看

一.日志 1.日志和备份的必要性 日志刷新 2.mysql的日志类型 &#xff08;1&#xff09;错误日志 查看当前错误日志和是否记录警告设置 &#xff08;2&#xff09;通用查询日志 查看通用查询日志的设置 &#xff08;3&#xff09;二进制日志 查看二进制文件的设置&…