【数据结构与算法(C语言)】循环队列图解
目录
- 1. 前言
- 1.1 普通循环队列假溢出
- 1.1.1 初始化队列
- 1.1.2 插满队列
- 1.1.3 删除元素后,再插入元素
- 1.2 循环队列
- 1.2.1 插入元素,队列已满
- 1.2.2 将元素J1、J2出列,循环队列又空出两个空间
- 1.2.3 元素J6可以继续入列
- 2. 存储结构和函数说明
- 2.1 队列的结构
- 2.2 基本操作函数
- 2.3 初始化队列
- 2.4 销毁队列 DestroyQueue
- 2.5 清空队列 ClearQueue
- 2.6 获取队列第一个元素 GetHead
- 2.7 获取队列长度
- 2.8 元素入列 EnQueue
- 2.9 元素出列 DeQueue
- 2.10 遍历队列 QueueTraverse
- 3. 完整源码和测试代码
- 4. 测试结果
- 5. 小结
- 5.1 优点:
- 5.2 缺点
1. 前言
将队列的头尾相接,臆造成环状的顺序存储结构称为循环队列。
普通的顺序存储队列会出现 假溢出 情况。如下面三张图(三个步骤)描述的情况
1.1 普通循环队列假溢出
下面来看看普通队列是如何产生假溢出现象的。
1.1.1 初始化队列
此时队列为空队列。头指针和尾指针都指向第一个空间

1.1.2 插满队列
插入J1、J2、J3、J4、J5、J6,因为q->rear=6,说明队列已满

1.1.3 删除元素后,再插入元素
删除J1,J2,按道理应该是空出两个空间,可以插入新元素,但此时q ->rear指向6号地址,还是判定队列已满,如果再插入元素,q-rear=7,则队列溢出。但实际队列是有空间的

1.2 循环队列
普通的循环队列有上述假溢出缺点。于是乎,循环队列就应运而生了。
循环队列的解决假溢出方法 如下面三张图中展示的步骤:
1.2.1 插入元素,队列已满
还剩一个空间的时候,队列就满了。这样设置的原因是,如果不浪费一个空间的话,当 queue.front=queue.rear,可能会有两种情况,一个是队列为空,一个是队列已满。如果预留一个空间的话,可以用 queue.rear + 1=queue.front 判断队列已满,这样和队列为空的判断方式不冲突。

1.2.2 将元素J1、J2出列,循环队列又空出两个空间

1.2.3 元素J6可以继续入列

2. 存储结构和函数说明
2.1 队列的结构
typedef struct{QElemType * base; //存储空间 int front; //队列头的下标int rear; //队列尾的下标
}SqQueue; //定义一个队列类型
2.2 基本操作函数
和上一篇博客中的链式队列差不多,一共8个函数。
Status InitQueue(SqQueue * queue); //初始化队列
void DestroyQueue(SqQueue *queue); //销毁队列
Status ClearQueue(SqQueue * queue);//清空队列
Status QueueEmpty(SqQueue queue); //判断队列是否为空
Status GetHead(SqQueue queue ,QElemType * e); //获取队列头元素
int QueueLength(SqQueue queue); //获取队列长度
Status EnQueue(SqQueue * queue, QElemType e); //元素入列
Status DeQueue(SqQueue * queue ,QElemType * e); //元素出列
2.3 初始化队列
原型:Status InitQueue(SqQueue * queue)
说明:初始化队列,申请一个头结点的内存
/*初始化队列,申请一个头结点的内存*/
Status InitQueue(SqQueue * queue)
{queue->base = (QElemType *) malloc(sizeof(QElemType)*MAXSIZE); //申请一个队列结点作为头结点的内存地址给 队头指针;if(queue->base == NULL)return FALSE;queue->front = queue->rear =0;return TRUE;
}
2.4 销毁队列 DestroyQueue
原型 :void DestroyQueue(SqQueue *queue)
功能 :销毁队列,释放队列的数据空间
/*销毁栈,释放队列的数据空间*/
void DestroyQueue(SqQueue *queue)
{free(queue->base);queue->front= queue->rear =0;
}
2.5 清空队列 ClearQueue
原型:Status ClearQueue(SqQueue * queue)
功能 :清空队列的元素,但队列的空间保留
//将队列queue清空
Status ClearQueue(SqQueue * queue)
{queue->front = queue->rear = 0;return OK;
}
2.6 获取队列第一个元素 GetHead
原型:Status GetHead(SqQueue queue ,QElemType * e)
功能 :获取队列第一个元素,注意 不是删除元素
//获取队列第一个元素
Status GetHead(SqQueue queue ,QElemType * e)
{if(QueueEmpty(queue))return FALSE;*e=queue.base[queue.front];return TRUE;
}
2.7 获取队列长度
原型:int QueueLength(SqQueue queue)
功能 :队列长度
//返回队列长度
int QueueLength(SqQueue queue)
{return (queue.rear - queue.front + MAXSIZE) % MAXSIZE;
}
2.8 元素入列 EnQueue
原型:Status EnQueue(SqQueue * queue, QElemType e)
功能 :元素e 插入队列queue
//元素e 插入队列queue
Status EnQueue(SqQueue * queue, QElemType e)
{if((queue->rear + 1) % MAXSIZE == queue->front) //队列满,return FALSE ;queue->base[queue->rear]=e; //e 插入队列尾部,队尾加1queue->rear = (queue->rear + 1) % MAXSIZE;return TRUE;
}
2.9 元素出列 DeQueue
原型:Status DeQueue(SqQueue * queue ,QElemType * e)
功能 :若队列queue不空,则删除Q的队头元素,用e返回其值,并返回 OK;否则返回ERROR
//若队列queue不空,则删除Q的队头元素,用e返回其值,并返回 OK;否则返回ERROR
Status DeQueue(SqQueue * queue ,QElemType * e)
{if(QueueEmpty( *queue))return FALSE;*e = queue->base[queue->front];queue->front= (queue->front + 1) % MAXSIZE;return TRUE;
}
2.10 遍历队列 QueueTraverse
原型:Status QueueTraverse(SqQueue queue,void (*visit)())
功能 :遍历队列,对队列的每个元素调用Visit函数
//遍历队列,对队列的每个元素调用Visit函数
Status QueueTraverse(SqQueue queue,void (*visit)())
{int i = queue.front;if(QueueEmpty(queue))return FALSE ;if(queue.front < queue.rear) while(i < queue.rear)visit(queue.base[i++]);else{while(i< MAXSIZE)visit(queue.base[i++]);i=0;while(i<queue.rear)visit(queue.base[i++]);}return TRUE;
}
3. 完整源码和测试代码
#include <stdio.h>
#include <stdlib.h>#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define MAXSIZE 6 //最大值设置为6typedef int Status;typedef int QElemType; //定义元素类型为整型typedef struct{QElemType * base; //存储空间 int front; //队列头的下标int rear; //队列尾的下标
}SqQueue; //定义一个队列类型 Status InitQueue(SqQueue * queue);
void DestroyQueue(SqQueue *queue);
Status ClearQueue(SqQueue * queue);
Status QueueEmpty(SqQueue queue);
Status GetHead(SqQueue queue ,QElemType * e);
int QueueLength(SqQueue queue);
Status EnQueue(SqQueue * queue, QElemType e);
Status DeQueue(SqQueue * queue ,QElemType * e);/*初始化队列,申请一个头结点的内存*/
Status InitQueue(SqQueue * queue)
{queue->base = (QElemType *) malloc(sizeof(QElemType)*MAXSIZE); //申请一个队列结点作为头结点的内存地址给 队头指针;if(queue->base == NULL)return FALSE;queue->front = queue->rear =0;return TRUE;
}/*销毁队列,释放队列的数据空间*/
void DestroyQueue(SqQueue *queue)
{free(queue->base);queue->front= queue->rear =0;
}//将队列queue清空
Status ClearQueue(SqQueue * queue)
{queue->front = queue->rear = 0;return OK;
}//判断队列是否为空
Status QueueEmpty(SqQueue queue)
{return queue.front == queue.rear? TRUE:FALSE;
}//获取队列第一个元素
Status GetHead(SqQueue queue ,QElemType * e)
{if(QueueEmpty(queue))return FALSE;*e=queue.base[queue.front];return TRUE;
}//返回队列长度
int QueueLength(SqQueue queue)
{return (queue.rear - queue.front + MAXSIZE) % MAXSIZE;
}//元素e 插入队列queue
Status EnQueue(SqQueue * queue, QElemType e)
{if((queue->rear + 1) % MAXSIZE == queue->front) //队列满,return FALSE ;queue->base[queue->rear]=e; //e 插入队列尾部,队尾加1queue->rear = (queue->rear + 1) % MAXSIZE;return TRUE;
}//若队列queue不空,则删除Q的队头元素,用e返回其值,并返回 OK;否则返回ERROR
Status DeQueue(SqQueue * queue ,QElemType * e)
{if(QueueEmpty( *queue))return FALSE;*e = queue->base[queue->front];queue->front= (queue->front + 1) % MAXSIZE;return TRUE;}
void Visit(QElemType e)
{printf("%3d",e);
}
//遍历队列,对队列的每个元素调用Visit函数
Status QueueTraverse(SqQueue queue,void (*visit)())
{int i = queue.front;if(QueueEmpty(queue))return FALSE ;if(queue.front < queue.rear) while(i < queue.rear)visit(queue.base[i++]);else{while(i< MAXSIZE)visit(queue.base[i++]);i=0;while(i<queue.rear)visit(queue.base[i++]);}return TRUE;
}int main()
{QElemType e;SqQueue queue;InitQueue(&queue);printf("队头分别插入数字3、4、5、6、7后:");//此时队列已经满了,设置maxsize=6,实际只能存储5个,//因为只剩一个空间,代表队列已满。即 front= (rear+1)%maxsize//如果不留一个空间空着,那么队列满和队列空都是 front=rear,很难分辨EnQueue(&queue,3);EnQueue(&queue,4);EnQueue(&queue,5);EnQueue(&queue,6);EnQueue(&queue,7);QueueTraverse(queue,Visit);printf("\n继续插入数字8");if(EnQueue(&queue,8))printf("\n出问题了,队列满了,还能插入!");elseprintf("\n队列已满,无法插入!");printf("\n删除队头数字后:");DeQueue(&queue,&e); //删除后的队列中还剩4个元素QueueTraverse(queue,Visit);printf("\n继续插入8数字后:");EnQueue(&queue,8); //数字8被存放到queue.base[5]中了QueueTraverse(queue,Visit);printf("\n清空队列");ClearQueue(&queue);printf("\n队列长度:%d\n",QueueLength(queue));DestroyQueue(&queue);getchar();return 0;
}
4. 测试结果

5. 小结
循环队列的优缺点
5.1 优点:
(a) 解决了普通的顺序存储队列的假溢出问题。
(b) 读取方便、快捷
5.2 缺点
存储空间大小固定,无法根据需要进行扩展。
相关文章:
【数据结构与算法(C语言)】循环队列图解
目录 1. 前言1.1 普通循环队列假溢出1.1.1 初始化队列1.1.2 插满队列1.1.3 删除元素后,再插入元素 1.2 循环队列1.2.1 插入元素,队列已满1.2.2 将元素J1、J2出列,循环队列又空出两个空间1.2.3 元素J6可以继续入列 2. 存储结构和函数说明2.1 队…...
私域流量转化不济的原因
你是不是也曾感到私域流量的转化一直不如意?让我来告诉你,这六大问题是为什么,以及如何轻松解决它们,提升你的私域流量转化率! 1. 问题:目标不明确 你是否常常感到茫然,不知道私域流量应该有何目…...
百万上下文RAG,Agent还能这么玩
❝ 在AI技术飞速发展的今天,我们见证了许多令人惊叹的突破。最近,Qwen2模型的开源引起了广泛的关注,它不仅展示了超越闭源模型的能力,还带来了一个全新的框架——Qwen-Agent。 Qwen-Agent的设计思路虽然与LangChain相似࿰…...
【后端开发】服务开发场景之高可用(冗余设计,服务限流,降级熔断,超时重试,性能测试)
【后端开发】服务开发场景之高可用(冗余设计,服务限流,降级熔断,超时重试,性能测试) 文章目录 序:如何设计一个高可用的系统?可用性的判断指标是什么?哪些情况会导致系统…...
在 Selenium 中更改 User-Agent | 步骤与最佳实践
在 Selenium 中更改 User Agent 是许多网页抓取任务中的关键步骤。它有助于将自动化脚本伪装成常规浏览器,从而避免被网站检测到。本指南将带您了解如何在 Selenium 中更改 Google Chrome 的 User Agent,并提供最佳实践以确保您的网页抓取任务顺利进行。…...
2024酒店IPTV云桌面系统建设方案
Hello大家好,我是点量小芹,这一年多的时间一直在分享实时云渲染像素流相关的内容,今天和大家聊聊酒店IPTV云桌面电视系统解决方案,或者有的朋友也会称之为IPTV服务器。熟悉小芹的朋友知道,IPTV软件系统是我们一直在推的…...
java Thrift TThreadPoolServer 多个processor 的实现
当我们使用Thrift 通信的时候,服务端有时候需要注册多个类,去实现通信,这时候我们就不能再使用单一Processor的方式,就要使用多个Processor,那么如何去实现呢? 多个Process 服务端 public static void m…...
失眠焦虑的解脱之道:找回内心的平静
🍃 在这个快节奏的时代,失眠与焦虑似乎成了许多人的隐形敌人。每当夜幕降临,它们便悄悄潜入心底,扰乱我们的思绪,让宁静的夜晚变得无比漫长。然而,生活总有办法让我们找回内心的平静,只需稍作调…...
OLED柔性屏的显示效果如何
OLED柔性屏的显示效果非常出色,具有多方面的优势。以下是关于OLED柔性屏显示效果的详细分析: 色彩表现:OLED柔性屏的每个像素都可以独立发光,因此色彩准确性极高。黑色呈现得非常深邃,而亮部则展现出鲜明而生动的细节。…...
百货商城优选 伊利牛奶推出全国首款减甲烷环保学生奶
近日,伊利集团受邀参加在全国首个“国际首脑峰会零碳场馆”召开的“降碳增产科技助力奶业绿色高质量发展”首款低碳饲料创新大会。会上,伊利宣布将推出全国首款减甲烷环保学生牛奶——伊利QQ星学生纯牛奶,进一步将可持续发展落到实处…...
Fluid 1.0 版发布,打通云原生高效数据使用的“最后一公里”
作者:顾荣 前言 得益于云原生技术在资源成本集约、部署运维便捷、算力弹性灵活方面的优势,越来越多企业和开发者将数据密集型应用,特别是 AI 和大数据领域应用,运行于云原生环境中。然而,云原生计算与存储分离架构虽…...
软件测试--第十一章 设计和维护测试用例
1.单选题 (2分) 下面有关测试设计的叙述,说法不正确的是( )。 A 测试用例的设计是一项技术性强.智力密集型的活动 B 在开展测试用例设计前,必须将测试需求进行详细展开 C 在一般的测试组织内,测试用例的评审可能不是正式的评审会 D 在测试用例设计时,只设计覆盖正常流程和操…...
前端只允许一次函数调用
如果你正在进行前端开发,并且只想允许一次函数调用,你可以使用JavaScript的闭包结构创建一个只能被调用一次的函数。这样的函数有时被称为单次调用函数(“one-time call” functions)或一次性函数(“once” functions&…...
visdom使用时所遇的问题及解决方法
最近在用visdom进行可视化的过程中,虽然可有效的避免主机拒绝访问(该问题的解决方法,请参考深度学习可视化工具visdom使用-CSDN博客)即在终端输入python -m visom.server 1.训练过程中visdom出现ValueError: too many file descr…...
密封类(sealed class)
在 Kotlin 中,密封类(sealed class)是一种受限的类层次结构,允许您定义一个封闭的类层次结构,其中类的所有可能子类都已知并且位于同一文件中。密封类的主要作用是提供类型安全的受限层次结构,使得 when 表…...
私域引流宝PHP源码 以及搭建教程
私域引流宝PHP源码 以及搭建教程...
磁盘管理 以及磁盘的分区 详细版
磁盘管理 track:磁道,就是磁盘上同心圆,从外向里,依次1号、2号磁道sector:扇区,将磁盘分成一个一个扇形区域,每个扇区大小是512字节,从外向里,依次是1号扇区、2号扇区cylinder&…...
加码多肤色影像技术 这是传音找到的“出海利器“?
全球化时代,市场竞争愈演愈烈,产品差异化已然成为了企业脱颖而出的关键。在黄、白肤色长期占据人像摄影主赛道的背景下,传音就凭借独一无二的多肤色影像技术走出非洲,走向了更广阔的新兴市场。 聚焦深肤色人群拍照痛点,…...
C++方法封装成dll及C#调用示例
1,编译生成dll时可能出现错误,解决办法:pch.h文件头部,添加声明 #define _CRT_SECURE_NO_WARNINGS 2, c头文件声明 extern "C" __declspec(dllexport) char* getvalue(const char * param1, const char * param2); 3, c方法实现…...
定时清理Linux服务器缓存shell脚本
服务器内存占用过高,如何定时清理一下服务器内存呢?写一个清理缓存脚本,加入到定时任务中。 一、编写脚本 clear_cache.sh 脚本,放到home目录下。 #!/bin/bash# 清除页面缓存、目录项和 inode 缓存 sudo sync echo 3 | sudo tee /proc/sys/vm/drop_caches# 记录执行时间到日…...
Zustand 状态管理库:极简而强大的解决方案
Zustand 是一个轻量级、快速和可扩展的状态管理库,特别适合 React 应用。它以简洁的 API 和高效的性能解决了 Redux 等状态管理方案中的繁琐问题。 核心优势对比 基本使用指南 1. 创建 Store // store.js import create from zustandconst useStore create((set)…...
智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql
智慧工地管理云平台系统,智慧工地全套源码,java版智慧工地源码,支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求,提供“平台网络终端”的整体解决方案,提供劳务管理、视频管理、智能监测、绿色施工、安全管…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
UDP(Echoserver)
网络命令 Ping 命令 检测网络是否连通 使用方法: ping -c 次数 网址ping -c 3 www.baidu.comnetstat 命令 netstat 是一个用来查看网络状态的重要工具. 语法:netstat [选项] 功能:查看网络状态 常用选项: n 拒绝显示别名&#…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...
mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
关于uniapp展示PDF的解决方案
在 UniApp 的 H5 环境中使用 pdf-vue3 组件可以实现完整的 PDF 预览功能。以下是详细实现步骤和注意事项: 一、安装依赖 安装 pdf-vue3 和 PDF.js 核心库: npm install pdf-vue3 pdfjs-dist二、基本使用示例 <template><view class"con…...
Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
