设计循环队列-C语言实现

题目描述

设计循环队列

设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于
FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。

循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。

你的实现应该支持如下操作:

MyCircularQueue(k): 构造器,设置队列长度为 k 。 Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。 enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。 isEmpty(): 检查循环队列是否为空。 isFull():
检查循环队列是否已满。

思路讲解

这道题目的意思就是设计一个循环队列,队列的大小是固定的,但可以一直排队插入数据,如果队列空间满了就排队等在后面,队列释放出了空间之后,又可以插入新的数据,就像一个固定的内存空间,可以插入数据在数据满的时候也可以删除数据,循环使用。
这里我们用数组的形式来设计一个循环队列,为什么要用数组来设计循环队列,而不用链表,那是因为,数组比链表更加方便访问,而链表操作起来会更加复杂一些,我们这里的空间是固定的,而不是随机的,开辟数组就相当于开辟了内存中可以连续存放的空间,访问数据的速度和链表相比更快。
我们这里最主要考虑的问题就是,在什么时候判断队列里面的数据存放满了,还有什么时候队列是空的
我们来画图看看
在这里插入图片描述
现在我们往里面插入数据,采用尾插,头不动
在这里插入图片描述
这样我们的数据就插满我们的队列了,我们首先把head 和tail都置为0,tail指向存放元素的下一个位置当tail把6插入完的时候tail已经完成回绕回到开头了就是head这个位置,发现当head == tail的时候我们的队列就插入满了
现在我们来删除元素,动head,tail不动。
在这里插入图片描述
现在发现删除元素删完之后,也是tail == head,这时候问题就来了,到底何时队列存满了数据,还有何时队列是空的,这里我们提出了一个解决方法,再在数组后面新添加一个空间,这个新添加的空间就是用来解决,队列判满这种情况的,这样我们可以把判满的条件改成head == tail+1
在这里插入图片描述
为什么这样可以解决问题,tail始终是指向有元素的下一个位置,当我们的插入满了的时候,我们的tail就指向了新开的空间,新开的空间指向的下一个就要回绕到开头,也就是头节点,所以 当tail +1 == head的时候队列就插入满了,而删除还是 当head == tail 不受影响。
当想明白这个问题之后,我们就可以开始写代码了,

代码分析

typedef struct {
    int* data;
    int head;
    int tail;
    int k;
} MyCircularQueue;

首先创建我们的整体结构,然后根据题意创建我们的队列

MyCircularQueue* myCircularQueueCreate(int k) {

MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
 obj-> data = (int*)malloc(sizeof(int)*(k+1));//k+1就代表新增的一个空间
 obj-> head = 0;
 obj-> tail = 0;
 obj->k = k;
 return obj;
}

这里力扣给的obj的定义是这样的
在这里插入图片描述

到这我们的队列就初始化完成了
下面是插入

插入队列

//插入
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))//调用判满函数,如果判满就返回false
    {
        return false;
    }
    else
    {
        obj->data[obj->tail] = value;//在尾巴后面插入
        obj->tail++;//尾巴位置++
        obj->tail = obj->tail%(obj->k+1);
        return true;
    }
}

这里我们主要说一下这行代码

   obj->tail = obj->tail%(obj->k+1);

这里主要是判断回绕,如果不采取判断何时回绕的话,数组就越界了,这里的设计很巧妙,采用取模的方式来判断
在这里插入图片描述
这里我们可以看到,当队列空间存放满的时候tail就指向了新开的空间tail就等于6,但插入完成之后ail本身也要++,就变成7,而K+1本身就等于7,7%7 = 0;就返回到数组开头了,完成了回绕,如果tail小于K+1,对K+1取模,就等于tail本身,这时就代表不需要回绕

删除队列

//删除
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))//删除前要判空
    {
        return false;
    }
    else
    {
       obj->head++;//删除直接向前覆盖就行了
       obj->head = obj->head%(obj->k+1);
       return true;
    }
}

删除也和插入一样需要判断回绕问题,同样也是采用取模的方式判断

判满

下面是代码

bool myCircularQueueIsFull(MyCircularQueue* obj) {

       return (obj->tail+1)%(obj->k+1) == obj->head;
}

判满也是采用取模的方式进行的,我们还是拿这张图来看
在这里插入图片描述
这里的tail在插入最后一个数据之后变成7,7去%k+1,就是0,而0就是head的位置,就代表队列满了,所以通过这个表达式就可以判满。

取队头

/拿头
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        return obj->data[obj->head];
    }
}

这里就没什么好说的了,就先判断队列是不是空的,然后返回头就行了。

取队尾数据

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        return obj->tail == 0? obj->data[obj->k]:obj->data[obj->tail-1];
    }
}

这里最主要的就是这行代码

return obj->tail == 0? obj->data[obj->k]:obj->data[obj->tail-1];

这里主要判断tail有两种情况,一种是普通的,tail就在队列中间,就像这样,这种我们就直接返回tail-1就行了
在这里插入图片描述
还有一种情况是tail完成回绕之后处于0处,这种如果直接减一就变成负数了,就像下面这张图
在这里插入图片描述
这里当tail == 0的时候我们就直接让他返回队列的最后一个元素下表位置也就是k。

判空

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->tail == obj->head;
}

这里就直接可以看tail和head相等不相等。

释放空间

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

这里注意不能直接把obj释放了,要先释放他指向的那个数组,在释放它本身

源码

typedef struct {
    int* data;
    int head;
    int tail;
    int k;
} MyCircularQueue;
//要前置声明一下
MyCircularQueue* myCircularQueueCreate(int k);
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value);
bool myCircularQueueDeQueue(MyCircularQueue* obj);
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);
int myCircularQueueFront(MyCircularQueue* obj);
int myCircularQueueRear(MyCircularQueue* obj);

MyCircularQueue* myCircularQueueCreate(int k) {

MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
 obj-> data = (int*)malloc(sizeof(int)*(k+1));
 obj-> head = 0;
 obj-> tail = 0;
 obj->k = k;
 return obj;
}
//插入
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    else
    {
        obj->data[obj->tail] = value;
        obj->tail++;
        obj->tail = obj->tail%(obj->k+1);
        return true;
    }
}
//删除
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    else
    {
       obj->head++;
       obj->head = obj->head%(obj->k+1);
       return true;
    }
}
//判满
bool myCircularQueueIsFull(MyCircularQueue* obj) {

       return (obj->tail+1)%(obj->k+1) == obj->head;
}
//拿头
int myCircularQueueFront(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        return obj->data[obj->head];
    }
}

int myCircularQueueRear(MyCircularQueue* obj) {
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        return obj->tail == 0? obj->data[obj->k]:obj->data[obj->tail-1];
    }
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->tail == obj->head;
}

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

/**
 * Your MyCircularQueue struct will be instantiated and called as such:
 * MyCircularQueue* obj = myCircularQueueCreate(k);
 * bool param_1 = myCircularQueueEnQueue(obj, value);
 
 * bool param_2 = myCircularQueueDeQueue(obj);
 
 * int param_3 = myCircularQueueFront(obj);
 
 * int param_4 = myCircularQueueRear(obj);
 
 * bool param_5 = myCircularQueueIsEmpty(obj);
 
 * bool param_6 = myCircularQueueIsFull(obj);
 
 * myCircularQueueFree(obj);
*/

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

FPGA verilog LVDS通信协议笔记

一幅图胜过千言万语 直接开始挫代码,先写top.v。 module top();reg clk; // 生成时钟的寄存器 reg rst; // 生成复位信号的寄存器initial clk 1; // 初始值取1 always #1 clk ~clk; //1ns取反一次initial begin // 复位信号,先0,过段时间赋…

ORA-00932: inconsistent datatypes: expected - got CLOB的分析解决方案

最近在项目中遇到查询数据时报ORA-00932: inconsistent datatypes: expected - got CLOB错误,这个错误很明显是由于查询时类型的不匹配造成的。 问题分析: 一、检查你的查询的实体的类型是否于数据库的保持一致,如果不一致,那么需…

Rumor Remove Order Strategy on Social Networks

ABSTRACT 谣言被定义为广泛传播且没有可靠来源支持的言论。现代社会,谣言在社交网络上广泛传播。谣言的传播给社会带来了巨大的挑战。 “假新闻”故事可能会激怒您的情绪并改变您的情绪。有些谣言甚至会造成社会恐慌和经济损失。因此,谣言的影响可能是深…

Redis-数据过期策略

文章目录 Redis数据持久化策略的作用是什么?Redis的数据过期策略有哪些?惰性删除定期删除 更多相关内容可查看 Redis数据持久化策略的作用是什么? Redis数据过期策略是指在Redis中设置数据的过期时间,并在数据过期时自动从数据库…

【JavaScript超详细的学习笔记-上】JavaScrip超详细的学习笔记,共27部分,12多万字

想要获取笔记的可以点击下面链接获取 JavaScript超详细的学习笔记,点击我获取 一,JavaScript详细笔记 1,基础知识 1-1 基础知识 // 1,标识符命名规则:第一个字母必须是字母,下划线或一个美元符号。不能…

pasmutility.dll丢失要怎么修复,pasmutility.dll破解补丁在哪里找到?

pasmutility.dll是电脑中非常重要的文件之一,当电脑突然弹出“找不到pasmutility.dll”或是“pasmutility.dll丢失”等的错误提示窗口,可以选择下载pasmutility.dll文件,当然除了下载的方法还有很多种关于pasmutility.dll丢失的解决方法&…

自作聪明的AI? —— 信息处理和传递误区

一、背景 在人与人的信息传递中有一个重要问题——由于传递人主观处理不当,导致信息失真或产生误导。在沟通交流中,确实存在“自作聪明”的现象,即传递人在转述或解释信息时,根据自己对信息的理解、经验以及个人意图进行了过多的…

LeetCode 125题:验证回文串

❤️❤️❤️ 欢迎来到我的博客。希望您能在这里找到既有价值又有趣的内容,和我一起探索、学习和成长。欢迎评论区畅所欲言、享受知识的乐趣! 推荐:数据分析螺丝钉的首页 格物致知 终身学习 期待您的关注 导航: LeetCode解锁100…

Apache访问控制与虚拟主机

目录 一. Web服务简介 以下是一些 Web 服务的基本概念和特征 以下是一些主流的 Web 服务器 WEB 服务协议 二. Apache 服务的搭建与配置 2.1 Apache 介绍 2.2 Apache安装 2.3 Apache目录介绍 三. 访问控制 四. 修改默认网站发布目录 五. 虚拟主机 5.1 基于域名的虚拟…

Linux信息显示相关指令

1、查看cpu 查看cpu信息:cat /proc/cpuinfo 查看cpu个数:nproc cat /proc/cpuinfo | grep "physical id" | uniq | wc -l uniq命令:删除重复行;wc –l命令:统计行数 查看CPU核数 cat /proc/cpuinfo | grep "cpu cores" | uniq 2、查看内存 cat /pr…

【STM32 |程序实例】按键控制、光敏传感器控制蜂鸣器

目录 前言 按键控制LED 光敏传感器控制蜂鸣器 前言 上拉输入:若GPIO引脚配置为上拉输入模式,在默认情况下(GPIO引脚无输入),读取的GPIO引脚数据为1,即高电平。 下拉输入:若GPIO引脚配置为下…

Android adb shell关于CPU核的命令

Android adb shell关于CPU核的命令 先使用命令: adb shell 进入控制台。 然后,直接在$后面输入下面命令,针对CPU的命令。 cat /proc/cpuinfo | grep ^processor | wc -l 查看当前手机的CPU是几核的。 cat sys/devices/system/cpu/online …

Ansible常用变量【下】

转载说明:如果您喜欢这篇文章并打算转载它,请私信作者取得授权。感谢您喜爱本文,请文明转载,谢谢。 前言 在上一篇文章《Ansible常用变量【上】》中,学习了Ansible常用变量的前半部分,放了个五一假&#x…

LeetCode1207独一无二的出现次数

题目描述 给你一个整数数组 arr,请你帮忙统计数组中每个数的出现次数。如果每个数的出现次数都是独一无二的,就返回 true;否则返回 false。 解析 正常的解法肯定是对每个元素使用一个hashmap,存元素及出现次数,然后通…

使用Apache Spark从MySQL到Kafka再到HDFS的数据转移

使用Apache Spark从MySQL到Kafka再到HDFS的数据转移 在本文中,将介绍如何构建一个实时数据pipeline,从MySQL数据库读取数据,通过Kafka传输数据,最终将数据存储到HDFS中。我们将使用Apache Spark的结构化流处理和流处理功能&#…

【Linux】调试器-gdb使用

大家好,我是苏貝,本篇博客带大家了解Linux的编译器-gcc/g,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️ 目录 1. 背景(A) 看大小(B) 查看ELF格式的文件 2.使用(A) 进入gdb(B) quit/q&#xff…

flink优化案例

文章目录 一、flink join维表案例二、flink 双流join案例三、总结 提示:以下是本篇文章正文内容,下面案例可供参考(适用于flink1.13) 一、flink join维表案例 背景:flink sql join 维表。job业务不复杂,job写入性能比较差。维表数据大约每天…

想半天憋不出几个字?试试AI扩写

大家在写文章时是否也经常这样?想了半天,结果只能写出几个字,但是要求往往又是几百多个字,那么有没有啥工具可以帮我们在原文的基础上扩写一下文章字数,让我们达到字数要求呢? 下面给大家介绍一下如何扩写文…

Microsoft Office for Mac 2024 (Office 365) 16.84 Universal 预览版

Microsoft Office for Mac 2024 (Office 365) 16.84 Universal 预览版 Office LTSC 2024 for Mac 请访问原文链接:Microsoft Office for Mac 2024 (Office 365) 16.84 Universal 预览版,查看最新版。原创作品,转载请保留出处。 作者主页&a…

FullCalendar日历组件集成实战(2)

背景 有一些应用系统或应用功能,如日程管理、任务管理需要使用到日历组件。虽然Element Plus也提供了日历组件,但功能比较简单,用来做数据展现勉强可用。但如果需要进行复杂的数据展示,以及互动操作如通过点击添加事件&#xff0…