Leetcode:622. 设计循环队列 题解【具详细】

2023-11-23 08:04

本文主要是介绍Leetcode:622. 设计循环队列 题解【具详细】,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、题目:

二、思路详解:

1.循环队列的存储定义

2.循环队列的创建

3.循环队列的判空与判断情况

(1) 循环队列的判空:

 (2) 循环队列的判满

4.循环队列元素的插入

5.循环队列元素的删除

6.获取队头元素

7.获取队尾元素 

8.循环队列释放

三、完整代码展示:


一、题目:

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

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

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

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

难度:中等

题目链接:622. 设计循环队列

示例:

MyCircularQueue circularQueue = new MyCircularQueue(3); // 设置长度为 3
circularQueue.enQueue(1);  // 返回 true
circularQueue.enQueue(2);  // 返回 true
circularQueue.enQueue(3);  // 返回 true
circularQueue.enQueue(4);  // 返回 false,队列已满
circularQueue.Rear();  // 返回 3
circularQueue.isFull();  // 返回 true
circularQueue.deQueue();  // 返回 true
circularQueue.enQueue(4);  // 返回 true
circularQueue.Rear();  // 返回 4

题目解析:就是根据题中给的接口进行函数的实现。要求我们实现一个循环队列。

用心阅读下方会有很大的收获。 

二、思路详解:

1.循环队列的存储定义

首先我们需要定义出一个循环队列的存储定义,这里采用的是使用动态数组来进行模拟循环队列,根据题中给出的接口返回类型,我们可以知道循环队列的数据类型为int 。

其次,还需定义两个记录数组的下标,一个记录队列的队头,另一个记录队列的队尾(也就是指向要入队的下一个元素的位置)。另外还要提供一个表示要存储数据的具体个数。

如图:

代码:

//采用动态数组的形式来模拟循环队列
typedef struct {int* a;     //指向数组int front;  //队头int tail;   //队尾int k;      //数据个数
} MyCircularQueue;

2.循环队列的创建

循环队列的创建,先使用malloc进行创建一个 循环队列空间

接着根据给的数据个数k让指针a指向一个动态数组,在分别对front,tail,k进行初始化,注意tail = 0表示要存放的下一个数据元素的位置,对动态数组a开辟空间的时候要多开辟一个空间,避免假溢出的现象。最后一定要返回之前创建的循环队列。

代码:

//创建长度为k的循环队列
MyCircularQueue* myCircularQueueCreate(int k) {//使用动态内存函数来申请内存//这里多申请一个空间的目的是防止假溢出//使用malloc创建一个循环队列MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//为循环队列里面的指针a ,让a指向一个长度为k+1的数组obj->a= (int*)malloc(sizeof(int)*(k+1));obj->front = 0; //队头从数组的下标0开始obj->tail = 0; //队尾指向下一个元素obj->k = k; //队列的长度为kreturn obj;
}

物理存储情况,如图:

但是我们一般会到其循环的逻辑结构,逻辑存储,如图:

 3.循环队列的判空与判断情况

循环队列的插入和删除是不可避免的,当这之前就需要先完成判和判满的接口。注意:一定要把判空和判满的函数实现放在队列插入和删除函数实现的前面。

(1) 循环队列的判空:

根据函数的返回类型是bool,空我们就返回true ,否则返回false。

  • isEmpty(): 检查循环队列是否为空。

因为这里采取的是通过动态数组来模拟循环队列,所以队列空的条件就是当front == tail 的时候,此时的循环队列就是空的。

如图:

代码:

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//队空,就是队头与队尾相同时return obj->front == obj->tail;
}
 (2) 循环队列的判满

 同样根据函数的返回类型是bool,空我们就返回true ,否则返回false。

  • isFull(): 检查循环队列是否已满。

什么时候会满呢?当(tail+1)%(k+1) == front,就是队尾下标加1模开辟空间的个数 

可能很多会对为什么要多开辟一个空间,原因就在这:对于队列的判满的情况,

当没有创建的额外空间,队列只有数据10 和 11 的情况下,

像上图就是假溢出现象,这个队列并没有满。

总的来说:

循环队列为了区分队列的空和满,需要额外增加一个空的元素来占据队列的一个位置,这样队列满的状态就可以通过头尾指针相邻且不重合来判断,而不会出现头尾指针重合但队列实际上并不满的情况。同时循环队列需要对头尾指针进行模运算,如果没有额外的空间,那么当队列最后一个元素占据了数组最后一个位置时,下一个元素就会从数组的第一个位置开始,这样就无法正确进行模运算,而增加一个空的元素可以解决这个问题。

 代码:

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

 4.循环队列元素的插入

  • enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。

插入前判断是否满,满就返回false,接着就是数据的插入,插入后,对tail下标进行取模(因为是反复利用原来的空间,还有就是避免溢出),插入成功就返回true。

 代码:

//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//插入元素前先进行判断是否满if(myCircularQueueIsFull(obj)){return false;}//插入元素使用尾插obj->a[obj->tail] = value;obj->tail++;//避免tail的下标越界obj->tail%=(obj->k+1);return true;
}

5.循环队列元素的删除

 删除前,要进行判断是否为空。队头减一,进行删除,删除后取模。

  • deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。

 代码:

//出队
bool myCircularQueueDeQueue(MyCircularQueue* obj) {//删除元素队列不能为空if(myCircularQueueIsEmpty(obj)){return false;}//出队,头删obj->front++;obj->front%=(obj->k+1);return true;
}

 6.获取队头元素

获取前进行判断,是否为空。

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

  代码:

//获取队首元素
int myCircularQueueFront(MyCircularQueue* obj) {//队列不能为空if(myCircularQueueIsEmpty(obj)){return -1; //队空返回-1}return obj->a[obj->front];
}

7.获取队尾元素 

获取前进行判断,是否为空。

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

  代码:

//获取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {//队列不能为空if(myCircularQueueIsEmpty(obj)){return -1; //队空返回-1}//注意当tail = 0的情况return obj->a[(obj->tail - 1+ obj->k+1)%(obj->k+1)];
}

解释一下 上述最后一行代码:

重点:

首先tail是指向要存放下一个元素的位置,找队尾元素时,tail要进行-1。

 因为数组下标最小是从0开始的,当tail ==0且队列不为空的情况下,上方代码obj->tail-1,就会造成0-1 == -1的情况。上方采用(obj->tail - 1+ obj->k+1)%(obj->k+1)就可以完美的避免,当然

其实可以写成

int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;// return obj->a[(obj->tail-1 + obj->k+1)%(obj->k+1)];if(obj->tail == 0){return obj->a[obj->k];}else{return obj->a[obj->tail-1];}
}

8.循环队列释放

 因为用malloc开辟的动态内存空间,为了避免内存泄漏,我们还要释放内存。注意释放的顺序。

 代码:

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

三、完整代码展示:

 代码: 


//采用动态数组的形式来模拟循环队列
typedef struct {int* a;     //指向数组int front;  //队头int tail;   //队尾int k;      //数据个数
} MyCircularQueue;//创建长度为k的循环队列
MyCircularQueue* myCircularQueueCreate(int k) {//使用动态内存函数来申请内存//这里多申请一个空间的目的是防止假溢出//使用malloc创建一个循环队列MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//为循环队列里面的指针a ,让a指向一个长度为k+1的数组obj->a= (int*)malloc(sizeof(int)*(k+1));obj->front = 0; //队头从数组的下标0开始obj->tail = 0; //队尾指向下一个元素obj->k = k; //队列的长度为kreturn obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//队空,就是队头与队尾相同时return obj->front == obj->tail;
}bool myCircularQueueIsFull(MyCircularQueue* obj) {return (obj->tail+1)%(obj->k+1) == obj->front;
}//插入元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {//插入元素前先进行判断是否满if(myCircularQueueIsFull(obj)){return false;}//插入元素使用尾插obj->a[obj->tail] = value;obj->tail++;//避免tail的下标越界obj->tail%=(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; //队空返回-1}return obj->a[obj->front];
}//获取队尾元素
int myCircularQueueRear(MyCircularQueue* obj) {//队列不能为空if(myCircularQueueIsEmpty(obj)){return -1; //队空返回-1}//注意当tail = 0的情况return obj->a[(obj->tail - 1+ obj->k+1)%(obj->k+1)];
}void myCircularQueueFree(MyCircularQueue* obj) {free(obj->a);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);
*/

这篇关于Leetcode:622. 设计循环队列 题解【具详细】的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/416506

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1180(广搜+优先队列)

此题要求最少到达目标点T的最短时间,所以我选择了广度优先搜索,并且要用到优先队列。 另外此题注意点较多,比如说可以在某个点停留,我wa了好多两次,就是因为忽略了这一点,然后参考了大神的思想,然后经过反复修改才AC的 这是我的代码 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<

poj 3190 优先队列+贪心

题意: 有n头牛,分别给他们挤奶的时间。 然后每头牛挤奶的时候都要在一个stall里面,并且每个stall每次只能占用一头牛。 问最少需要多少个stall,并输出每头牛所在的stall。 e.g 样例: INPUT: 51 102 43 65 84 7 OUTPUT: 412324 HINT: Explanation of the s

poj 2431 poj 3253 优先队列的运用

poj 2431: 题意: 一条路起点为0, 终点为l。 卡车初始时在0点,并且有p升油,假设油箱无限大。 给n个加油站,每个加油站距离终点 l 距离为 x[i],可以加的油量为fuel[i]。 问最少加几次油可以到达终点,若不能到达,输出-1。 解析: 《挑战程序设计竞赛》: “在卡车开往终点的途中,只有在加油站才可以加油。但是,如果认为“在到达加油站i时,就获得了一

怎么让1台电脑共享给7人同时流畅设计

在当今的创意设计与数字内容生产领域,图形工作站以其强大的计算能力、专业的图形处理能力和稳定的系统性能,成为了众多设计师、动画师、视频编辑师等创意工作者的必备工具。 设计团队面临资源有限,比如只有一台高性能电脑时,如何高效地让七人同时流畅地进行设计工作,便成为了一个亟待解决的问题。 一、硬件升级与配置 1.高性能处理器(CPU):选择多核、高线程的处理器,例如Intel的至强系列或AMD的Ry

基于51单片机的自动转向修复系统的设计与实现

文章目录 前言资料获取设计介绍功能介绍设计清单具体实现截图参考文献设计获取 前言 💗博主介绍:✌全网粉丝10W+,CSDN特邀作者、博客专家、CSDN新星计划导师,一名热衷于单片机技术探索与分享的博主、专注于 精通51/STM32/MSP430/AVR等单片机设计 主要对象是咱们电子相关专业的大学生,希望您们都共创辉煌!✌💗 👇🏻 精彩专栏 推荐订阅👇🏻 单片机

leetcode-24Swap Nodes in Pairs

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode swapPairs(L

leetcode-23Merge k Sorted Lists

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode mergeKLists