【数据结构与算法(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 缺点

存储空间大小固定,无法根据需要进行扩展。

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

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

相关文章

vivado PIP or SITE_PIP、PKGPIN_BYTEGROUP

PIP是Xilinx部件上用于路由连接或网络的设备对象。PIP 称为ARC的连接多路复用器可以编程为将一根电线连接到 另一个&#xff0c;从而将节点连接在一起&#xff0c;以形成中特定NET所需的路由 设计。 SITE_PIP&#xff0c;也称为路由BEL&#xff0c;是SITE内部的连接多路复用器&…

android常用知识

透明activity样式&#xff1a; android:theme"android:style/Theme.Translucent.NoTitleBar.Fullscreen"这句代码&#xff0c;当你是建的empty activity project时&#xff0c;默认继承的是AppCompat这个类。所以在AndroidMifext.xml文件中用上述代码会导致程序错误&…

Qt | 简单的使用 QStyle 类(风格也称为样式)

01、前言 者在 pro 文件中已添加了正确的 QT+=widgets 语句 02、基础样式 1、QStyle 类继承自 QObject,该类是一个抽像类。 2、QStyle 类描述了 GUI 的界面外观,Qt 的内置部件使用该类执行几乎所有的绘制,以确保 使这些部件看起来与本地部件完全相同。 3、Qt 内置了一系…

制造业为什么需要ERP企业管理软件?

如今&#xff0c;传统的制造业管理方式逐渐变得力不从心~库存积压、生产效率低下、供应链混乱…想象一下&#xff0c;如果你的企业仍然依赖于手工记录订单、库存和财务数据&#xff0c;那么每当市场发生变动时&#xff0c;你就需要花费大量的时间和精力去重新调整生产计划、更新…

【深度学习驱动流体力学】VTK创建、处理和可视化流体数据

Visualization Toolkit&#xff08;VTK&#xff09;是一个强大的开源软件系统&#xff0c;用于处理和可视化三维数据。它提供了丰富的工具和算法&#xff0c;可以处理从简单的网格数据到复杂的流体动力学模拟数据等各种类型的数据。本文将完整介绍如何使用 VTK 创建、处理和可视…

Springboot + Mybatis 实现sql打印

参照这个视频&#xff1a;https://www.bilibili.com/video/BV1MS411N7mn/?vd_source90ebeef3261cec486646b6583e9f45f5 实现mybatis对外暴露的接口Interceptor 使用Intercepts接口,这里的写法参照mybatis-plus中的拦截器写法 Intercepts({Signature(type Executor.class, m…

BC153 [NOIP2010]数字统计

数字统计 一.题目描述二.输入描述&#xff1a;三.输出描述&#xff1a;四.数字范围五.题目思路六.代码实现 一.题目描述 请统计某个给定范围[L, R]的所有整数中&#xff0c;数字2出现的次数。 比如给定范围[2, 22]&#xff0c;数字2在数2中出现了1次&#xff0c;在数12中出现1次…

如何恢复iPhone iCloud云盘资料删除?给出建议

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

【Java】已解决com.mysql.cj.jdbc.exceptions.CommunicationsException异常

文章目录 一、分析问题背景二、可能出错的原因三、错误代码示例四、正确代码示例五、注意事项 已解决com.mysql.cj.jdbc.exceptions.CommunicationsException异常 一、分析问题背景 com.mysql.cj.jdbc.exceptions.CommunicationsException是Java程序在使用MySQL Connector/J与…

目标检测—Fast RCNN

介绍Fast R-CNN之前先简单回顾一下R-CNN和SPP-net R-CNN&#xff08;Regions with CNN&#xff09; affine image wraping 解析 Bounding Box Regression&#xff08;边界框回归&#xff09; 如何回归&#xff1f; 问题1&#xff1a;为什么要使用相对坐标差&#xff1f; …

立创开源学习篇(一)

1.机壳地 外面包围的一圈是机壳地&#xff0c;和金属外壳相连与电路板的GND不相连&#xff1a;&#xff08;大疆很多产品有此设计&#xff09; 屏蔽和接地&#xff1a;通过在电路板周围打孔&#xff0c;并连接到机壳地&#xff0c;可以形成有效的电磁屏蔽层&#xff08;形成金…

【C语言】回调函数 和 部分库函数的用法以及模拟实现

一、回调函数&#xff1a; 1、定义&#xff1a; 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针&#xff08;地址&#xff09;作为参数传递给另一个函数&#xff0c;当这个指针被用来调用其所指向的函数时&#xff0c;我们就说这是回调函数。 2、qsort的模拟实现…

怎样打印微信文档文件?

在日常生活和工作中&#xff0c;我们经常需要打印微信中的文档文件&#xff0c;无论是工作资料、学习笔记还是其他重要信息。随着科技的发展&#xff0c;我们不再需要前往打印店进行繁琐的操作&#xff0c;而是可以通过一些便捷的在线打印平台轻松实现。今天&#xff0c;我们就…

echarts学习:通过图例事件实现选中后控制多条折线的显隐

1.问题描述 我在工作中遇到了这样一个需求&#xff1a;我们都知道点击echarts折线图的图例&#xff0c;是可以控制折线的显隐的。我现在希望点击某一个图例可以改变多条折线的显隐。 例如在下面这张图中&#xff0c;我将“xxx水位”和“yyy水位”分为一组&#xff1b;将“xxx…

SGPT论文阅读笔记

这是篇想要用GPT来提取sentence embedding的工作&#xff0c;提出了两个框架&#xff0c;一个是SGPT-BE&#xff0c;一个是SGPT-CE&#xff0c;分别代表了Bi-Encoder setting和Cross-Encoder setting。CE的意思是在做阅读理解任务时&#xff0c;document和query是一起送进去&am…

Maven 配置学习:存在两个本地私服如何配置

Maven 配置学习&#xff1a;存在两个本地私服如何配置 目录 Maven 配置学习&#xff1a;存在两个本地私服如何配置解释&#xff1a;1.本地仓库位置&#xff1a;2.Profiles 定义&#xff1a;3.Repositories 定义顺序&#xff1a;4.Active Profiles&#xff1a; 操作步骤&#xf…

在Pycharm使用Github Copilot

文章目录 1.GitHub Copilot 是什么2.注册GitHub Copilot3.官方使用文档4.安装 GitHub Copilot插件5.在Pycharm中使用6.相关功能键7.启用或禁用 GitHub Copilot 1.GitHub Copilot 是什么 GitHub Copilot 是一款 AI 编码助手&#xff0c;可帮助你更快、更省力地编写代码&#xff…

【MySQL进阶之路 | 高级篇】SQL执行过程

1. 客户端与服务器的连接 运行中的服务器程序与客户端程序本质上都是计算机的一个进程&#xff0c;所以客户端进程向服务器端进程发送请求并得到相应过程的本质就是一个进程间通信的过程. 我们可以使用TCP/IP网络通信协议&#xff0c;命名管道和共享内存等方式&#xff0c;实…

2024/6/18(RBAC,查询用户权限,细粒度授权,选课,支付宝生成二维码支付,支付结果查询需要内网穿透)

黑马程序员【学成在线项目】,P141 测试沙箱支付宝_黑马学成在线支付宝沙箱-CSDN博客 需要内网穿透

31.加载配置文件中的游戏到辅助列表

上一个内容&#xff1a;30.保存游戏配置到文件 以 30.保存游戏配置到文件 它的代码为基础进行修改 效果图&#xff1a; 加载配置文件到列表的函数&#xff1a; void CWndINJ::LoadGame() {int count GetPrivateProfileInt(L"main", L"count", 0, GameI…