DS:循环队列的实现

news2025/1/16 8:14:18

                                                 创作不易,给个三连吧!! 

一、前言

对于循环队列,博主也是源自于一道力扣的OJ题

力扣:循环队列的设置

      后来我在网上查过,这个循环队列是有自己的应用场景的!!并不是出题者为了出题而产生的,所以我觉得不光要能做会这道题,还得多去探究这道题的不同方式。而且这道题虽然是循环队列,看似好像要把头和尾连起来,但实际上实现过程中是可以不需要的!这也是他非常特别的一点,因此在这我会重点介绍他的数组实现和链式结构实现。

二、数组实现循环队列

怎么用数组去实现循环队列呢?我们来画图研究一下:

2.1 结构体的创建

typedef int QDataType;
typedef struct MyCircularQueue
{  
	QDataType* a;//动态数组
	int capacity;//记录循环队列的容量
	int front;//记录队首
	int rear;//记录队尾
} MyCircularQueue;

2.2 构造一个k长度的队列并返回

根据我们之前的思路,我们要多创建一块空间!!

MyCircularQueue* myCircularQueueCreate(int k) 
{
	MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
	if (obj == NULL)
	{
		perror("malloc obj fail");
		exit(1);
	}
	obj->a = (QDataType*)malloc(sizeof(QDataType) * (k + 1));
	if (obj->a == NULL)
	{
		perror("malloc obj->a fail");
		exit(1);
	}
	obj->front = obj->rear = 0;
	obj->capacity = k;
	return obj;
}

2.3 向循环队列插入一个元素。如果成功插入则返回真。 

我们要往循环队列中插入一个元素,那么首先必须确保队列不为满(后面会封装),那我们之前分析过队列不为满的情况是rear指针的下一个位置是front,但是我们要注意一个特殊情况,如下图:

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

 但是我们要注意的是实际上我们是多开了一个空间!!!%的时候要把多的空间算上

2.4 向循环队列删除一个元素。如果成功删除则返回真。

我们要往循环队列中删除一个元素,那么首先必须确保队列不为空(后面会封装),front++就行了,同样front也会遇到上面这种情况,处理当时一样,++完后%上数组的实际大小

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

2.5 从队首获取元素。如果队列为空,返回 - 1 

直接取头指针就行了

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

2.6 从队尾获取元素。如果队列为空,返回 - 1 

要注意rear指针指向的是最后一个元素的下一个位置,所以要取得的话就要找到rear的前一个位置的下标,这里我们不能直接让rear--,因为我们只是获取队列尾的元素,并不能去改变rear的指向,所以我们要算出rear前面那个位置的下标,其实也是一样,利用%的修正,让rear加上数组实际大小-1,然后再%数组的大小,就刚还是rear前面的位置的下标了!!

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

2.7 判断循环队列是否为空

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

2.8 判断循环队列是否为满

bool myCircularQueueIsFull(MyCircularQueue* obj)
{
	return (obj->rear + 1)%(obj->capacity + 1) ==obj->front;//rear为k的时候正好
}

2.9 销毁循环队列

void myCircularQueueFree(MyCircularQueue* obj)
{
	free(obj->a);//没必要置空,因为obj用不了,obj->a也用不了  front rear k 也没必要释放
	free(obj);
	//obj = NULL;
}

2.10 全部代码

2.10.1 MyCircularQueue.h

#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>

typedef int QDataType;
typedef struct MyCircularQueue
{  
	QDataType* a;//动态数组
	int capacity;//记录循环队列的容量
	int front;//记录队首
	int rear;//记录队尾
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k);//构造一个k长度的队列
bool myCircularQueueEnQueue(MyCircularQueue* obj, QDataType value);// 向循环队列插入一个元素。如果成功插入则返回真。
bool myCircularQueueDeQueue(MyCircularQueue* obj);// 向循环队列删除一个元素。如果成功删除则返回真。
int myCircularQueueFront(MyCircularQueue* obj); //从队首获取元素。如果队列为空,返回 - 1 。
int myCircularQueueRear(MyCircularQueue* obj);//从队尾获取元素。如果队列为空,返回 - 1 。
bool myCircularQueueIsEmpty(MyCircularQueue* obj);//判断循环队列是否为空
bool myCircularQueueIsFull(MyCircularQueue* obj);//判断循环队列是否为满
void myCircularQueueFree(MyCircularQueue* obj);//销毁循环队列

 2.10.2 MyCircularQueue.c

#include"MyCircularQueue.h"

MyCircularQueue* myCircularQueueCreate(int k) 
{
	MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
	if (obj == NULL)
	{
		perror("malloc obj fail");
		exit(1);
	}
	obj->a = (QDataType*)malloc(sizeof(QDataType) * (k + 1));
	if (obj->a == NULL)
	{
		perror("malloc obj->a fail");
		exit(1);
	}
	obj->front = obj->rear = 0;
	obj->capacity = k;
	return obj;
}

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

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
	if (myCircularQueueIsEmpty(obj))
		return false;
	obj->front++;
	obj->front %= (obj->capacity + 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->capacity) % (obj->capacity + 1)];
}

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

bool myCircularQueueIsFull(MyCircularQueue* obj)
{
	return (obj->rear + 1)%(obj->capacity + 1) ==obj->front;//rear为k的时候正好
}

void myCircularQueueFree(MyCircularQueue* obj)
{
	free(obj->a);//没必要置空,因为obj用不了,obj->a也用不了  front rear k 也没必要释放
	free(obj);
	//obj = NULL;
}

2.11 相关选择题

5.现有一循环队列,其队头指针为front,队尾指针为rear;循环队列长度为N。其队内有效长度为?(假设队头不存放数据)( ?)
A (rear - front + N) % N + 1
B (rear - front + N) % N
C (rear - front) % (N + 1)
D (rear - front + N) % (N - 1)

答:这题就是根据我们上面那道题的一个变形,所以我们知道肯定是%上长度的,所以可以直接选B

三、链式结构实现循环队列

怎么用链式结构来实现循环队列呢?我们来分析一下:

3.1 结构体的创建

我们按照链式队列的思路,创建一个队列结构体来管理头尾指针,同时加上capacity(容量)和size(有效数据)

typedef int QDataType;
typedef struct QNode
{
	struct QNode* next;//节点
	QDataType val;//数据域
}QNode;

typedef struct MyCircularQueue
{
	QNode* front;//链表的头指针
	QNode* rear;//链表的尾指针
	int capacity;//记录链表的容量
	int size;//记录链表的有效节点
}MyCircularQueue;

3.2 构造一个k长度的队列并返回

MyCircularQueue* myCircularQueueCreate(int k)
{
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    if (obj == NULL)
    {
        perror("malloc fail");
        exit(1);
    }
    obj->front = obj->rear = NULL;
    obj->size = 0;
    obj->capacity = k;
    return obj;
}

3.3 向循环队列插入一个元素。如果成功插入则返回真。

bool myCircularQueueEnQueue(MyCircularQueue* obj, QDataType value)
{
    //如果为满了,直接就返回false
    if (myCircularQueueIsFull(obj))
        return false;
    //不满足就创建节点
    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    if (newnode == NULL)
    {
        perror("malloc fail");
        exit(1);
    }
    newnode->val = value;
    newnode->next = NULL;
    //创建成功,要考虑队列为空和不为空的情况
    if (myCircularQueueIsEmpty(obj))//为空,让新节点成为头
        obj->front = obj->rear = newnode;
    else//不为空,让tail继续往后遍历
    {
        obj->rear->next = newnode;
        obj->rear = newnode;
    }
    obj->size++;
    return true;
}

3.4 向循环队列删除一个元素。如果成功删除则返回真。

bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
    //为空就没有删的必要了
    if (myCircularQueueIsEmpty(obj))
        return false;
    //不为空,删除头节点,让下一个节点成为新的头,然后释放掉
    QNode* cur = obj->front->next;
    free(obj->front);
    obj->front = cur;
    obj->size--;
    return true;
}

3.5 从队首获取元素。如果队列为空,返回 - 1 

int myCircularQueueFront(MyCircularQueue* obj)
{
    //为空,返回1
    if (myCircularQueueIsEmpty(obj))
        return -1;
    //不为空,就获取头指针的数据
    return obj->front->val;
}

3.6 从队尾获取元素。如果队列为空,返回 - 1

int myCircularQueueRear(MyCircularQueue* obj)
{
    //为空,返回1
    if (myCircularQueueIsEmpty(obj))
        return -1;
    //不为空,就获取尾指针的数据
    return obj->rear->val;
}

3.7 判断循环队列是否为空

bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
    return obj->size == 0;
}

3.8 判断循环队列是否为满

bool myCircularQueueIsFull(MyCircularQueue* obj)
{
    return obj->size == obj->capacity;
}

3.9 销毁循环队列

void myCircularQueueFree(MyCircularQueue* obj)
{
    //本质是链表,要一个个释放
    QNode* pcur = obj->front;//用来遍历删除的
    while (pcur)
    {
        QNode* next= pcur->next;
        free(pcur);
        pcur = next;
    }
    free(obj);
}

3.10 全部代码

3.10.1 MyCircularQueue.h

#pragma once
#include<stdio.h>
#include<stdbool.h>
#include<stdlib.h>
#include<assert.h>

typedef int QDataType;
typedef struct QNode
{
	struct QNode* next;//节点
	QDataType val;//数据域
}QNode;

typedef struct MyCircularQueue
{
	QNode* front;//链表的头指针
	QNode* rear;//链表的尾指针
	int capacity;//记录链表的容量
	int size;//记录链表的有效节点
}MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k);//构造一个k长度的队列
bool myCircularQueueEnQueue(MyCircularQueue* obj, QDataType value);// 向循环队列插入一个元素。如果成功插入则返回真。
bool myCircularQueueDeQueue(MyCircularQueue* obj);// 向循环队列删除一个元素。如果成功删除则返回真。
int myCircularQueueFront(MyCircularQueue* obj); //从队首获取元素。如果队列为空,返回 - 1 。
int myCircularQueueRear(MyCircularQueue* obj);//从队尾获取元素。如果队列为空,返回 - 1 。
bool myCircularQueueIsEmpty(MyCircularQueue* obj);//判断循环队列是否为空
bool myCircularQueueIsFull(MyCircularQueue* obj);//判断循环队列是否为满
void myCircularQueueFree(MyCircularQueue* obj);//销毁循环队列

3.10.2 MyCircularQueue.c

MyCircularQueue* myCircularQueueCreate(int k)
{
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    if (obj == NULL)
    {
        perror("malloc fail");
        exit(1);
    }
    obj->front = obj->rear = NULL;
    obj->size = 0;
    obj->capacity = k;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, QDataType value)
{
    //如果为满了,直接就返回false
    if (myCircularQueueIsFull(obj))
        return false;
    //不满足就创建节点
    QNode* newnode = (QNode*)malloc(sizeof(QNode));
    if (newnode == NULL)
    {
        perror("malloc fail");
        exit(1);
    }
    newnode->val = value;
    newnode->next = NULL;
    //创建成功,要考虑队列为空和不为空的情况
    if (myCircularQueueIsEmpty(obj))//为空,让新节点成为头
        obj->front = obj->rear = newnode;
    else//不为空,让tail继续往后遍历
    {
        obj->rear->next = newnode;
        obj->rear = newnode;
    }
    obj->size++;
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
    //为空就没有删的必要了
    if (myCircularQueueIsEmpty(obj))
        return false;
    //不为空,删除头节点,让下一个节点成为新的头,然后释放掉
    QNode* cur = obj->front->next;
    free(obj->front);
    obj->front = cur;
    obj->size--;
    return true;
}

int myCircularQueueFront(MyCircularQueue* obj)
{
    //为空,返回1
    if (myCircularQueueIsEmpty(obj))
        return -1;
    //不为空,就获取头指针的数据
    return obj->front->val;
}

int myCircularQueueRear(MyCircularQueue* obj)
{
    //为空,返回1
    if (myCircularQueueIsEmpty(obj))
        return -1;
    //不为空,就获取尾指针的数据
    return obj->rear->val;
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
    return obj->size == 0;
}

bool myCircularQueueIsFull(MyCircularQueue* obj)
{
    return obj->size == obj->capacity;
}

void myCircularQueueFree(MyCircularQueue* obj)
{
    //本质是链表,要一个个释放
    QNode* pcur = obj->front;//用来遍历删除的
    while (pcur)
    {
        QNode* next= pcur->next;
        free(pcur);
        pcur = next;
    }
    free(obj);
}

四、总结

        我们会发现,在这边无论是用数组实现和链表实现,本质上我们只是从逻辑层次上把它认为是相连的,但是物理层次上并没有把它连在一起,虽然链表是可以做到相连的,但是相连的话会比较复杂,不相连我们也可以解决,只要保证我们能够控制得住边界问题就行!! 

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

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

相关文章

软件工具安装遇到bug、报错不知道怎么解决?看这里!

前言 本文举例了几个常见的软件工具使用问题&#xff0c;文末会提供一些我自己整理和使用的工具资料 。 "在追逐零 Bug 的路上&#xff0c;我们不断学习、改进&#xff0c;更加坚定自己的技术信念。让我们相信&#xff0c;每一个 Bug 都是我们成长的机会。" 一、VM…

全面解读视频生成模型Sora

2024年2月15日&#xff0c;OpenAI在其官网发布了《Video generation models as world simulators》的报告&#xff0c;该报告提出了作为世界模拟器的视频生成模型Sora。 OpenAI对Sora介绍如下&#xff1a; We explore large-scale training of generative models on video dat…

【Simulink系列】——动态系统仿真 之 连续系统线性连续系统

声明&#xff1a;本系列博客参考有关专业书籍&#xff0c;截图均为自己实操&#xff0c;仅供交流学习&#xff01; 一、连续系统定义 连续系统输出在时间上连续变化&#xff0c;而非间隔采样取值&#xff0c;满足以下条件&#xff1a; ①输出连续变化&#xff0c;变化的间隔…

解锁文档处理新境界:ONLYOFFICE编辑功能为开发者带来新机遇

引言 ONLYOFFICE最新发布的文档8.0版本带来了一系列引人注目的功能和优化&#xff0c;为用户提供了更强大、更高效的在线编辑体验。这次更新涵盖了多个方面&#xff0c;包括PDF表单、RTL支持、单变量求解、图表向导以及插件界面设计更新等。这些新功能不仅提升了文档处理的便利…

免费下载的指纹浏览器推荐,有效保护您的隐私安全

在这个数字化快速发展的时代&#xff0c;我们每天都在网上留下无数的足迹。无论是在线购物、社交媒体互动还是处理跨境电商事务&#xff0c;我们的每一次点击都可能被跟踪&#xff0c;我们的个人信息和隐私正处于风险之中。在网络世界中&#xff0c;一个简单的浏览器指纹就能暴…

智慧社区管理系统:构建未来的生活模式

在这个信息化、智能化的时代&#xff0c;我们期待的不再是简单的居住空间&#xff0c;而是一个集安全、便捷、舒适、环保于一体的智能化社区。为此&#xff0c;我们推出了全新的智慧社区管理系统&#xff0c;旨在将先进的科技力量引入社区管理&#xff0c;为居民提供更优质的生…

Python UnicodeDecodeError: ‘gbk‘ codec can‘t decode byte 0xa4 in position 49

0x00 错误 UnicodeDecodeError: gbk codec cant decode byte 0xa4 in position 49: illegal multibyte sequence 这个错误出现的场景是这样的&#xff1a; 我把一个在 Mac 电脑生成的 .txt 文件 拷贝到了 Windows 电脑上 在读取 .txt 文件内容时 出现了这个错误 应该是 编…

视频监控需求八问:视频智能分析/视频汇聚平台EasyCVR有何特性?

最近TSINGSEE青犀视频在与业内伙伴进行项目合作的过程中&#xff0c;针对安防监控可视化视频管理系统EasyCVR视频融合平台在电信运营商项目中的应用&#xff0c;进行了多方面的项目需求沟通。今天我们就该项目沟通为案例&#xff0c;来具体了解一下用户关心度较高的关于视频智能…

运行jar时提示缺少依赖的类

供应商丢过来一个jar&#xff0c;是用Java写的Windows桌面程序&#xff0c;运行jar时提示缺少依赖的类&#xff0c;一看就是打包没带依赖的库&#xff0c;下面是解决方法&#xff1a; 1、解压缩jar&#xff0c;查看 META-INF 目录下的 MANIFEST.MF&#xff0c;看看都引用了哪些…

十、图像像素点的与、或、非、异或操作

项目功能实现&#xff1a;对图片像素点进行与或非操作 按照之前的博文结构来&#xff0c;这里就不在赘述了 在OpenCV中&#xff0c;颜色是(B,G,R)通道排列 一、头文件 yuhuofei.h 定义一个YUHUOFEI类&#xff0c;里面声明了一个yuhuofei方法 #pragma once#include<openc…

盲盒小程序开发,线上盲盒平台的发展潜力

盲盒的出现给大众带来了全新的消费体验&#xff0c;目前&#xff0c;盲盒经济也是席卷了当代年轻人&#xff0c;一种新的商业模式就此出现。盲盒的玩法、种类也在不断创新进化&#xff0c;成为了吸引大众的消费形式。 当然&#xff0c;在当下盲盒稳步发展时期&#xff0c;也要…

国标GB28181视频监控平台EasyGBS为什么视频播放一会儿就无法播放了?

视频监控国标GB28181平台EasyGBS是基于安防行业标准协议国标GB28181协议接入的安防监控视频平台&#xff0c;平台可以支持多路设备同时接入&#xff0c;实现视频流的接入、转码、处理、分发等功能&#xff0c;可对外分发RTSP、RTMP、FLV、HLS、WebRTC等格式的视频流。国标GB281…

数据分析案例-2023年TOP100国外电影数据可视化

&#x1f935;‍♂️ 个人主页&#xff1a;艾派森的个人主页 ✍&#x1f3fb;作者简介&#xff1a;Python学习者 &#x1f40b; 希望大家多多支持&#xff0c;我们一起进步&#xff01;&#x1f604; 如果文章对你有帮助的话&#xff0c; 欢迎评论 &#x1f4ac;点赞&#x1f4…

C/C++ BM11 链表相加(二)

文章目录 前言题目解决方案一1.1 思路阐述1.2 源码 总结 前言 这道题使用链表来实现加法运算&#xff0c;主要是涉及到数据对位以及加法进位的处理。 题目 假设链表中每一个节点的值都在 0 - 9 之间&#xff0c;那么链表整体就可以代表一个整数。 给定两个这种链表&#xff0…

【Docker】集群容器监控和统计 Portainer基本用法

Portainer是一款轻量级的应用&#xff0c;它提供了图形化界面&#xff0c;用川于方便地管理Docker环境&#xff0c;包括单机环境和集群环境。 主要功能&#xff1a;实现集群容器的监控和统计 下载安装 官网&#xff1a;https://www.portainer.io 文档&#xff1a;https://do…

短剧App:引领移动娱乐新潮流

随着科技的飞速发展&#xff0c;人们对于娱乐的需求也在不断变化。近年来&#xff0c;短剧App逐渐崭露头角&#xff0c;成为了移动娱乐的新宠。本文将探讨短剧App的发展趋势、市场现状、用户需求以及开发过程中的关键因素。 一、短剧App的发展趋势 短剧App以其简短、精悍的特…

无可执行权限加载 ShellCode

简单来说就是可以直接加载可读内存中的加密 ShellCode&#xff0c;不需要解密&#xff0c;不需要申请新的内存&#xff0c;也不需要改可执行权限。应用不仅仅在上线&#xff0c;上线后的各种功能都可以通过 ShellCode 实现 1.查杀点 现状 在加载 ShellCode、使用 BOF 等时候…

Mysql如何优化数据查询方案

mysql做读写分离 读写分离是提高mysql并发的首选方案。 Mysql主从复制的原理 mysql的主从复制依赖于binlog&#xff0c;也就是记录mysql上的所有变化并以二进制的形式保存在磁盘上&#xff0c;复制的过程就是将binlog中的数据从主库传输到从库上。 主从复制过程详细分为3个阶段…

《英伟达-本地AI》--NVIDIA Chat with RTX-本机部署

阿丹&#xff1a; 突然发现公司给配置的电脑是NVIDIA RTX 4060的显卡&#xff0c;这不搞一搞本地部署的大模型玩一玩&#xff1f;&#xff1f;&#xff1f; 从0-》1记录一下本地部署的全过程。 本地模型下载地址&#xff1a; Build a Custom LLM with Chat With RTX | NVIDIA…

Rocky 8.9 Kubespray v2.24.0 在线部署 kubernetes v1.28.6 集群

文章目录 1. 简介2. 预备条件3. 基础配置3.1 配置hostname3.2 配置互信 4. 配置部署环境4.1 在线安装docker4.2 启动容器 kubespray4.3 编写 inventory.ini4.4 关闭防火墙、swap、selinux4.5 配置内核模块 5. 部署 1. 简介 kubespray​ 是一个用于部署和管理 Kubernetes 集群的…