循环队列的实现(附完整代码)

news2024/11/15 22:49:18
题目解读

在这里插入图片描述
本题是要求我们设计一个循环的队列,循环队列要有以下功能:
1.获取队首元素,若队列为空返回-1
2.获取队尾元素,若队列为空,则返回-1
3.插入元素,插入成功返回真
4.删除元素,删除成功返回真
5.检查队列是否为空
6.检查队列是否已满
首先我们可以将之前写的用链表实现的队列的代码拷贝到该题中,以便于循环队列的实现,然后开始构思。
循环队列的解释题目中也给出了解释:
循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”

解题构思

所以我们可以把循环队列先画图,他是一个环形的队列,并且首位相连尾接
在这里插入图片描述
那么,循环队列什么时候是满的,什么时候是空的呢?
其实,当队首和队尾在同一个位置时,这个时候队列就是空的,而当对头front的位置等于对尾rear的位置加1时,这个时候队列就是满的:
在这里插入图片描述
经过前面的构思,这个题目就很好理解了
但是还有一个问题很值得思考:
题目中对于循环队列的定义还有一个点很重要:
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
什么意思呢?

也就是说,循环队列中我们如果在栈满了之后还想存储值,也是可以的,但是就要反复地使用之前用过的空间,会将其覆盖,所以尾指针rear和头指针front的位置的下标是会有覆盖的变化的

我们将循环队列形象地转换成数组:
在这里插入图片描述

这样你就能理解我上面所说的问题了!
你可以看到,队列为空时,按照题目的意思,front的位置时为rear+1的,在上图中,其实front的位置是0,rear的位置是3。
他们之间的关系就需要我们来求证一下了,因为在循环队列这个环形队列中,无论插入还是删除,都是从队头(或者是队尾)进行操作的!
我们其实就可以发现front的位置是与队列最大存储元素有关联的,上图中最大存储个数是3,当front存入4个元素时,存完第3个就满了,这个时候就应该重新从front位置开始存储,所以front(rear)和存储个数k有着以下关系:
在这里插入图片描述
就是说无论front的位置怎么移动,他最终都是在1-k的范围之内的

front  =  front  %  ( k + 1 )

现在,我们就可以开始用代码实现循环队列:

循环队列的构造

我们首先定义一个结构体,就是循环队列的结构
首先就是front和rear分别为队首和队尾的下标位置
然后就是k,存储元素个数
还有数组a,存储元素

typedef struct 
{
    int front;
    int rear;
    int k;
    int* a;
} MyCircularQueue;

然后我们就可以构造一个循环队列了

MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a=(int*)malloc(sizeof(int)*(k+1));
    obj->front=obj->rear=0;
    obj->k=k;
    return obj;
}
判断循环队列是否为空

我们在前面的解题构思中就知道,当front和rear相等时,循环队列就为空了,所以我们直接返回obj->front==obj->rear,如果队列为空,就返回 1,队列不为空就返回0

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->front==obj->rear;
}
判断循环队列是否已满

当rear+1和front相等时就是满的
这里能这样写吗?答案是不能,他要除以k+1然后取余,和front的方法一样

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->rear+1)%(obj->k+1)==obj->front;
}
循环队列插入元素

如果队列已经满了我们就直接返回false即可
如果不是满的话就要将数组rear位置下标的值赋值为你要插入的元素的值
同时rear++,然后取余,最后返回true

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->a[obj->rear]=value;
    obj->rear++;
    obj->rear %= (obj->k+1);
    return true;
}
循环队列删除元素

当队列为空时就不能删了,返回-1
不为空时,我们就将front的位置往前移动,这样队首的元素就被删除了
同时记得取余

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front++;
    obj->front %= (obj->k+1);   
    return true;
}
获取循环队列队首元素

这个也很简单,直接返回数组的front下标位置的元素即可

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[obj->front];
}
获取循环队列尾首元素

返回队尾元素我们就要根据图来具体求下标的关系了
由于画图较为麻烦,作者水平很有限,故不画图,给上源码,诸位大佬自己琢磨

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}
循环队列的销毁

free循环队列目标的同时记得把数组也给free掉,不然可能会出现内存泄漏

void myCircularQueueFree(MyCircularQueue* obj) 
{
    free(obj->a);
    free(obj);
}

完整代码如下:

typedef struct 
{
    int front;
    int rear;
    int k;
    int* a;
} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a=(int*)malloc(sizeof(int)*(k+1));
    obj->front=obj->rear=0;
    obj->k=k;
    return obj;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->front==obj->rear;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->rear+1)%(obj->k+1)==obj->front;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->a[obj->rear]=value;
    obj->rear++;
    obj->rear %= (obj->k+1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front++;
    obj->front %= (obj->k+1);   
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[obj->front];
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}

void myCircularQueueFree(MyCircularQueue* obj) 
{
    free(obj->a);
    free(obj);
}

好了,今天的分享到这里就结束了,谢谢大家的支持!

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

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

相关文章

文件夹重命名:如何在文件夹名称左边插入关键字,简单步骤轻松完成

在电脑中管理文件时,经常需要对文件夹进行重命名,以便于更方便地查找和识别文件。有时候,需要在文件夹名称的左边插入一些关键字,通过重命名文件夹,可以更清晰、更准确地描述文件夹的内容,以便于更好地管理…

【数据结构】树与二叉树(廿四):树搜索给定结点的父亲(算法FindFather)

文章目录 5.3.1 树的存储结构5. 左儿子右兄弟链接结构 5.3.2 获取结点的算法1. 获取大儿子、大兄弟结点2. 搜索给定结点的父亲a. 算法FindFatherb. 算法解析c. 代码实现 3. 代码整合 5.3.1 树的存储结构 5. 左儿子右兄弟链接结构 【数据结构】树与二叉树(十九&…

vivado产生报告阅读分析20-QOR

Report QoR Suggestions report_qor_suggestions 命令是处理 QoR 建议对象时使用的主要命令。 QoR 建议对象会创建命令和属性来改善设计的时序性能( 欲知详情 , 请参阅 QoR 建议 ) 。 report_qor_suggestions 命令可执行两项任务 &am…

MFC添加窗体菜单栏和消息响应

在资源视图右键,添加资源,选择Menu,新建 添加的菜单在资源菜单的Menu目录下 双击直接编辑输入菜单 之后在要添加菜单的窗体的属性Menu里面填写菜单的ID就可以了 如何给菜单添加点击响应? OnCommand是MFC中的一个消息处理函数,用于处理在窗口或控件被激活时发出的WM_CO…

中伟视界:AI智能分析盒子实现全方位人车监测,保障管道安全

在油气管道长又无人的场景下,人和车的监测问题一直是一个难题。传统的监测手段往往存在盲区和误报问题,给管道运行安全带来了一定的隐患。然而,随着人工智能技术的不断发展,利用AI盒子的智能分析算法可以有效解决这一问题。 首先&…

python多线程为什么没有跑满CPU?

1、实验环境 Vmvare虚拟机:单处理器2核。 2、Python获取CPU使用率 import psutildef get_cpu_percent():cpu_percent psutil.cpu_percent(interval1)return cpu_percentwhile(1):cpu_percent get_cpu_percent()print("当前CPU占用率:{}%"…

PyCharm 安装插件Vue

一、打开PyCharm工具 File -> Settings -> Plugins 二、在项目中添加Vue.js的依赖项。 npm install vue 三、页面应用

我的第一个Arduino点灯程序

我简直难以相信,什么都不用配置,就这么几行代码,就可以blink了 void setup() {// Set up the built-in LED pin as an output:pinMode(PA1, OUTPUT); }void loop() {digitalWrite(PA1,!digitalRead(PA1));// Turn the LED from off to on, o…

3. 深入探究文件 IO

3. 深入探究文件 IO 1. Linux 系统如何管理文件1.1 静态文件与inode1.2 文件打开时的状态 2. 返回错误处理与errno2.1 strerror 函数2.2 perror 函数 3. 空洞文件4. O_APPEND 和 O_TRUNC5. 多次打开同一个文件6. 复制文件描述符6.1 dup6.2 dup2 7. 文件共享7.1 同一个进程中多次…

接口测试场景:怎么实现登录之后,需要进行昵称修改?

在接口测试中有一个这样的场景:登录之后,需要进行昵称修改,怎么实现? 首先我们分别看下登录、昵称修改的接口说明: 以上业务中补充一点,昵称修改,还需要添加请求头Authorization传登录获取的to…

Depends 下载

查看某个应用程序和动态库的依赖 属性查看是只支持WIN32 的,查看X64的动态库电脑会卡死 左边框可以查看动态库的依赖,右边 可以查看动态库的导出情况 链接:https://pan.baidu.com/s/1vUFrOuzTO_dfvvkHP0-UiQ 提取码:i09s

2. 流程控制|方法|数组|二维数组|递归

文章目录 流程控制代码块选择结构循环结构跳转控制关键字 方法方法的概述方法的重载Junit单元测试初识全限定类名 Debug 小技巧数组数组的基本概念数组的基本使用数组的声明数组的初始化 JVM内存模型什么是引用数据类型基本数据类型和引用数据类型的区别堆和栈中内容的区别 数组…

yolo系列中的一些评价指标说明

文章目录 一. 混淆矩阵二. 准确度(Accuracy)三. 精确度(Precision)四. 召回率(Recall)五. F1-score六. P-R曲线七. AP八. mAP九. mAP0.5十. mAP[0.5:0.95] 一. 混淆矩阵 TP (True positives):被正确地划分为正例的个数,即实际为正例且被分类器划分为正例…

ModuleNotFoundError: No module named ‘torch_sparse‘

1、卸载 先把torch-geometric、torch-sparse、torch-scatter、torch-cluster、 torch-spline-conv全部卸载了 pip uninstall torch-geometric torch-scatter torch-sparse torch-cluster torch-spline-conv 2.conda list确定PyTorch的版本,我的是1.10 3、确定下载地…

《斯坦福数据挖掘教程·第三版》读书笔记(英文版)Chapter 3 Finding Similar Items

来源:《斯坦福数据挖掘教程第三版》对应的公开英文书和PPT It is therefore a pleasant surprise to learn of a family of techniques called locality-sensitive hashing, or LSH, that allows us to focus on pairs that are likely to be similar, without hav…

使用bard分析视频内容

11月21日的bard update 更新了分析视频的功能,使用方法如下: 1、打开bard网站。https://bard.google.com/ 2、点击插件。 3、点击YouTube中的 research a topic 选项。 4、输入需要分析的内容: Please analyze how many technologies are in…

五种多目标优化算法(MOGWO、MOLPB、MOJS、NSGA3、MOPSO)求解微电网多目标优化调度(MATLAB代码)

一、多目标优化算法简介 (1)多目标灰狼优化算法MOGWO 多目标应用:基于多目标灰狼优化算法MOGWO求解微电网多目标优化调度(MATLAB代码)-CSDN博客 (2)多目标学习者行为优化算法MOLPB 多目标学习…

win10+ vs2017用cmake编译geos3.5.1

参考教程:使用CMake编译Geos3.5.0_cmake geos-CSDN博客 注意事项: 报错:在使用cmake编译geos-3.5.1的时候,会出现报错: CMake Error at CMakeLists.txt:330 (include): include could not find load file GenerateSou…

map和set的底层结构 --- AVL树的实现(万字图文详解)

AVL树的实现 底层结构1. AVL的概念2. AVL树节点的定义3. AVL树的插入分析 4. AVL树的旋转4.1 新节点插入较高右子树的右侧---右右:左单旋4.2 新节点插入较高左子树的左侧---左左:右单旋4.3 新节点插入较高右子树的左侧---右左:先右单旋再左单…

postman和Jmeter做接口测试的区别(经验之谈)

接口测试的目的 API 测试作为集成测试的一部分,经过被测应用的接口(API)来确定是否在功能、可靠性、性能和安全方面达到预期的软件测试。因为 API 都没有 GUI 界面,API 测试都是在通信层进行的。 1.建立接口用例集 Postman功能…