循环队列----数据结构

news2024/12/23 19:43:54

缘由

在队列的顺序存储中,采用第二种出队的方式,将头指针 +1 ,可以避免元素的移动,但是这样也出现了一个问题 "假溢出" ,如图:

当出现这种情况时:头指针和尾指针都指向了不可访问的地方(越界了),就无法在插入(入队)了,队列的空间还空着,却无法利用,这造成了空间的浪费。

为了使用到完全的空间(利用前面的空间),可以使用循环队列。(红色代表已经利用的空间)

如图,当 tail 的值为5时,他应该指向下标为 0 的空间,也就是将 tail 赋值为0。这样队列就首尾相连,变成了循环队列。

由于 头指针和尾指针的范围是 [ 0 , MAX_SIZE -1 ] ,一旦等于MAX_SIZE,就变为0,所以可以使用到取模操作,每次移动完,再对 MAX_SIZE 取模。

队列的判空判满

那出现下面这种情况还可以插入元素吗?如下图:

假如可以的话,再插入一个元素,那 tail +1 就为 3 ,这时会发现一个问题:该如何判断队列为空,如何判断队列满了,有些困难。

所以这种情况就无法再插入元素了,我们能使用到的空间只有 MAX_SIZE-1 个,其中一块空间是为了方便判断队列的状态,并不保存任何数据。

 判断队列为空的条件是:头指针与尾指针指向同一个位置;判断队列为满的条件是:尾指针的后一位是头指针。

 tail == head 为判空条件,结合之前的移动问题,所以不是 tail + 1 == head,而是 (tail + 1) % MAX_SIZE == head 为判满条件

如图( front 是头指针,rear 是尾指针):

获取元素个数

顺序队列中求元素个数的方法为 尾指针减去头指针 ,可是现在有两种情况:

一、头指针在尾指针的前面(tail >= head):元素个数为 tail - head

二、尾指针在头指针的前面(tail<head):元素个数为 head - tail + MAX_SIZE (由MAX_SIZE-(tail - head)化简而成)

取模操作可以将两种情况统一为一种:元素个数为 (head - tail + MAX_SIZE) % MAX_SIZE

具体实现

就是顺序队列改动了一下需要注意的点。

#include <iostream>

using namespace std;

//循环队列的定义
#define MAX_SIZE 5
typedef int DateElem;

typedef struct Queue
{
	DateElem date[MAX_SIZE];
	int head;			//头指针
	int tail;			//尾指针
}squeue;

//初始化循环队列
void InitQueue(squeue* sq)
{
	if (!sq) return;
	sq->head = 0;
	sq->tail = 0;
}


//判断循环队列是否满了
bool IsFull(squeue* sq)
{
	if (!sq) return false;
	if ((sq->tail+1)%MAX_SIZE == sq->head) //*
	{
		return true;
	}
	else
	{
		return false;
	}
}
//判断循环队列是否为空
bool IsEmpty(squeue* sq)
{
	if (!sq) return false;

	if (sq->head == sq->tail) 
	{
		return true;
	}
	else
	{
		return false;
	}
}

//循环队列入队
bool EnterQueue(squeue* sq, DateElem e)
{
	if (IsFull(sq))
	{
		cout << "无法插入元素" << e << ",队列已满。" << endl;
		return false;
	}

	sq->date[sq->tail] = e;
	sq->tail = (sq->tail + 1) % MAX_SIZE; //*
	return true;
}
//循环队列出队
bool PopQueue(squeue* sq, DateElem* date)
{
	if (!sq || IsEmpty(sq))
	{
		return false;
	}

	*date = sq->date[sq->head];
	sq->head = (sq->head + 1) % MAX_SIZE; //*
	return true;
}

//打印队列
bool PrintQueue(squeue* sq)
{
	if (!sq) return false;

	for (int i = sq->head; i != sq->tail; i = (i+1) %MAX_SIZE) //*
	{
		printf("%d ", sq->date[i]);
	}
	return true;
}

//获取队首元素
int GetHeadElem(squeue* sq)
{
	if (!sq || IsEmpty(sq)) return 0;

	return sq->date[sq->head];
}


//销毁(清空)队列
bool DestoryQueue(squeue* sq)
{
	if (!sq) return false;

	sq->head = 0;
	sq->tail = 0;
	return true;
}

//获取队列长度
int GetLength(squeue* sq)
{
	if (!sq) return 0;

	return (sq->tail - sq->head + MAX_SIZE) % MAX_SIZE; //*
}
int main(void)
{
	squeue* sq = new squeue;
	DateElem* s = new DateElem;
	InitQueue(sq);
	DateElem e = 0;

	int choose = -1;
	while (choose != 0)
	{
		cout << "1.入队" << endl
			<< "2.出队" << endl
			<< "3.打印队列" << endl
			<< "4.获取队首元素" << endl
			<< "5.获取队列长度" << endl
			<< "6.销毁队列" << endl
			<< "0.退出" << endl;
		cin >> choose;

		switch (choose)
		{
		case 1:
			cout << "请输入要入队的元素:";
			cin >> e;
			if (EnterQueue(sq, e))
			{
				cout << "入队成功" << endl;
			}
			else
			{
				cout << "入队失败" << endl;
			}
			break;
		case 2:
			if (PopQueue(sq, s))
			{
				cout << "出队的元素是:" << *s << endl;
			}
			else
			{
				cout << "出队失败" << endl;
			}
			break;
		case 3:
			cout << "队列中的元素是:";
			PrintQueue(sq);
			cout << endl;
			break;
		case 4:
			cout << "队首元素是:" << GetHeadElem(sq) << endl;
			break;
		case 5:
			cout << "队列的长度是:" << GetLength(sq) << endl;
			break;
		case 6:
			if (DestoryQueue(sq))
			{
				cout << "队列已销毁" << endl;
			}
			else
			{
				cout << "队列不存在" << endl;
			}
			break;
		case 0:
			cout << "退出成功" << endl;
			break;
		default:
			cout << "输入非法" << endl;
			break;

		}
	}
	return 0;
}

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

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

相关文章

Qt窗体设计的布局

本文介绍Qt窗体的布局。 Qt窗体的布局分为手动布局和自动布局&#xff0c;手动布局即靠手工排布各控件的位置。而自动布局则是根据选择的布局类型自动按此类型排布各控件的位置&#xff0c;使用起来比较方便&#xff0c;本文主要介绍Qt的自动布局。 1.垂直布局 垂直布局就是…

[AUTOSAR][网络管理] 什么是BusOff? 如何实现它?

文章目录 一、BusOff检测机制(1)简介(2)目录介绍(3)软件实现逻辑代码运行流程如下:二、测试方法(1)物理测试三、示例代码(1) busoff_recovery.c(2) busoff_recovery.h一、BusOff检测机制 (1)简介 CAN控制器可以判断出错误的类型是总线上暂时的数据错误(如外部干扰等…

分布式锁 - 理论篇

一、为什么需要分布式锁 二、分布式锁实现 1.分布式锁演进 - 基本原理 我们可以同时去一个地方“占坑”&#xff0c;如果占到&#xff0c;就执行逻辑。否则就必须等待&#xff0c;直到释放锁。“占坑”可以去redis&#xff0c;可以去数据库&#xff0c;可以去任何大家都能访…

树状数组学习笔记

树状数组 树状数组的用途&#xff0c;主要是可以以 O ( log ⁡ n ) O(\log n) O(logn) 的时间复杂度维护前缀和。 对于树状数组的使用&#xff0c;我们开一个数组 c&#xff0c;c[x] 表示 [ x − lowbit ( x ) 1 , x ] [x-\text{lowbit}(x)1,x] [x−lowbit(x)1,x] 的区间和…

图像超分辨率超分辨率NeRF论文阅读

文章目录 前置知识图像超分辨率《High-resolution image reconstruction with latent diffusion models from human brain activity》【CVPR23】《Dynamic High-Pass Filtering and Multi-Spectral Attention for Image Super-Resolution》【ICCV21】《DiffBIR: Towards Blind …

视频的二维码怎么做?教你一个实用技巧操作

现在扫码看视频越来越常见&#xff0c;很多人都会用这种方式来展示内容&#xff0c;比如展示环境、产品说明、自拍录像等等&#xff0c;让别人能够更快的获取内容。举个例子&#xff0c;当我们从淘宝或者其他购物平台买东西时&#xff0c;现在咨询客服询问使用说明时&#xff0…

HTML超链接标签

目录 1&#xff1a;页面间的链接 1.1 文字跳转&#xff1a; 1.2 图片跳转 2&#xff1a;锚链接 1&#xff1a;页面间的链接 1.1 文字跳转&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><t…

webpack(五)热更新

webpack-dev-serve 开启本地服务器 现状&#xff1a;打包后将index.html文件通过open in liveServe打开&#xff0c;我们继续修改js、html文件内容&#xff0c;页面没有变化。 解决方法&#xff1a; 方法一&#xff1a; 在打包命令后面加上--watch,重新打包后我们的终端不会终…

类的继承简介

一、声明格式&#xff1a; class 子类名&#xff1a;继承方式(public private protected) 父类名{子类成员表} 二、继承过程&#xff1a; 吸取父类成员——>改造父类成员——>添加新成员 三、作用&#xff1a; 子类会继承父类中的方法(不包括构造和析构函数)与属性 …

进阶JAVA篇-深入了解 List 系列集合

目录 1.0 List 类的说明 1.1 List 类的常用方法 1.2 List 集合的遍历方式 2.0 ArrayList 集合的底层原理 2.1 从 ArrayList 集合的底层原理来了解具有该特性的原因&#xff1a; 2.2 ArrayList 集合的优缺点 3.0 LinkedList 集合的底层原理 3.1 从 LinkedList 集合的底层原理来了…

卷积神经网络CNN学习笔记-卷积计算Conv2D函数的理解

目录 1.全连接层存在的问题2.卷积运算3.填充(padding)3.1填充(padding)的意义 4.步幅(stride)5.三维数据的卷积运算6.结合方块思考7.批处理8.Conv2D函数解析9.conv2d代码9.1 stride19.2 stride2 参考文章 1.全连接层存在的问题 在全连接层中&#xff0c;相邻层的神经元全部连接…

多线程-进阶

常见的锁策略 乐观锁和悲观锁 这不是两把具体的锁, 这是两类锁 乐观锁: 预测锁的竞争不是很激烈 悲观锁: 预测锁的竞争会很激烈 乐观和悲观说的都不是绝对的, 唯一的区分就是看预测锁竞争激烈程度的结论, 这两种锁的背后工作是截然不同的, 轻量级锁和重量级锁 轻量级锁加锁解…

浅谈人工智能视频分析技术的原理及行业场景应用

人工智能视频分析技术是利用计算机视觉、模式识别和深度学习算法等技术&#xff0c;对视频数据进行自动化处理和分析的过程。其基本工作原理包括以下几个步骤&#xff1a; 视频采集&#xff1a;通过摄像头或其他视频设备获取源视频数据。 视频预处理&#xff1a;对视频进行去噪…

如何更改eclipse的JDK版本

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、有时候导入一些网上的资源需要更换JDK二、使用步骤1. 总结 一、有时候导入一些网上的资源需要更换JDK 具体操作如下 二、使用步骤 1. 在eclipse上方工具栏找…

使用列表实现向量运算

向量内积 from operator import mul x [4, 6, 9] y [2, 2, 7] print(sum(map(mul, x, y)))相当于 x [4, 6, 9] y [2, 2, 7] print(sum((i*j for i, j in zip(x, y))))两个等长的向量对应元素相加 from operator import add x [4, 6, 9] y [2, 2, 7] print(list(map(ad…

一些经典的神经网络(第20天)

1. 经典神经网络&#xff08;LeNet&#xff09; LeNet是早期成功的神经网络&#xff1b; 先使用卷积层来学习图片空间信息 然后使用全连接层来转到到类别空间 【通过在卷积层后加入激活函数&#xff0c;可以引入非线性、增加模型的表达能力、增强稀疏性和解决梯度消失等问题…

基于RSSI的室内wifi定位系统 计算机竞赛

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; wifi室内定位系统 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;…

【经历】在职8个月->丰富且珍贵

在职8个月->丰富且珍贵 2021-3~2021-11&#xff1a;面试进入一家做400电话的公司&#xff0c;我进入公司时&#xff0c;加上我只有四个人(老板、人事、业务)&#xff0c;开发只有我&#xff0c;所以&#xff1a;产品~设计~前端~后端~测试~上线~维护~培训&#xff0c;只有我自…

并发性Socket通信源码(基于linux环境下多线程)

服务器端&#xff1a;server.c 1 #include <stdio.h>2 #include <stdlib.h>3 #include <unistd.h>4 #include <string.h>5 #include <arpa/inet.h>6 #include <pthread.h>7 void* working(void *arg);8 //信息结构体9 struct sockinfo10 …

烘焙蛋糕外卖小程序商城的作用是什么

随着经营成本上升及电商业态的冲击&#xff0c;传统烘焙蛋糕门店商家经营止步不前&#xff0c;加之口罩原因更是雪上加霜&#xff0c;引流拓客、经营转化复购大幅度降低&#xff0c;而线上又因外卖平台间的激烈竞争&#xff0c;导致中小烘焙蛋糕商家进退两难。 烘焙蛋糕店经营…