【LeetCode刷题指南】--设计循环队列
🔥个人主页:@草莓熊Lotso
🎬作者简介:C++研发方向学习者
📖个人专栏: 《C语言》 《数据结构与算法》《C语言刷题集》《Leetcode刷题指南》
⭐️人生格言:生活是默默的坚持,毅力是永久的享受。
前言:在前面的博客中我们完成了用队列实现栈以及栈实现队列这两个经典题,那么博主今天给大家分享的这个设计循环队列会比前面这两题难一点,大家下去之后可以自己画图来写写看
目录
设计循环队列:
解题过程:
代码演示:
设计循环队列:
题目链接:622. 设计循环队列 - 力扣(LeetCode)
题目描述:
题目示例:
思路: 利用数组结构实现循环队列的设计(循环链表也可以,但是数组更方便一点),循环队列的一些特性
- 队头删数据,队尾插入数据
- 给固定的空间,使用过程中不可以扩容
- 环形队列满就不能继续插入数据(即插入数据失败)
解题过程:
1.定义一个数组,队头队尾下标,以及标识空间大小的capacity。创建构造一个循环队列,申请k+1个空间,方便区分队列为满和为空
2.在实现往循环队列中插入元素和删除元素之前我们首先需要判断循环队列是否为空或者为满,判断方法如图,转换成代码就行了
3.往循环队列中插入元素:首先需要判断是否为满,循环队列为满就不能再插入数据了即插入数据失败,返回false。如果不为满就正常插入数据就可以了,但是出现越界情况需要特殊处理,所以我们在返回true之前都会先用rear%(k+1),这样如果越界会回到初始位置,没有越界也不会影响。
4.删除循环队列中的数据:删除数据首先不能为空,为空就返回false。如果不为空直接++front,但是如果front越界,跟上面rear的调整方法是一样的原理,这里就不再说了
5.获取循环队列队头数据:队列不能为空,为空就返回-1.不为空直接返回front下标所在位置的元素就行
6.获取循环队列队尾元素:首先队列不能为空,为空还是返回-1。如果队列不为空,我们取到的队尾元素其实是下标为prev的元素,prev有两种情况,一般就是rear-1,如果rear回到了初始位置0时就把prev设置到capacity位置上。最后返回prev下标所在位置的元素就行了
7.循环队列的销毁:如果数组不为空,先销毁动态申请的数组空间,再释放掉我们的队列并置为空就行了
综合图示如下:
复杂度:
- 时间复杂度:初始化和每项操作的时间复杂度均为 O(1)。
- 空间复杂度:O(k),其中 k 为给定的队列元素数目。
代码演示:
typedef struct { int*arr; int front;//队头 int rear;//队尾 int capacity;//有效空间大小} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) { MyCircularQueue*cq=(MyCircularQueue*)malloc(sizeof(MyCircularQueue)); //申请k+1个空间 cq->arr=(int*)malloc((k+1)*sizeof(int)); cq->front=cq->rear=0; cq->capacity=k; return cq;}bool myCircularQueueIsEmpty(MyCircularQueue* obj) { //rear==front时为空 return obj->rear==obj->front;}bool myCircularQueueIsFull(MyCircularQueue* obj) { //(rear+1)%(k+1)==front时为满 return (obj->rear+1)%(obj->capacity+1)==obj->front;}bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) { //满了就不能插入数据 if(myCircularQueueIsFull(obj)) { return false; } //没满就插入数据,rear越界就调整回初始位置 obj->arr[obj->rear++]=value; obj->rear=obj->rear%(obj->capacity+1); return true;}bool myCircularQueueDeQueue(MyCircularQueue* obj) { //为空不能删除 if(myCircularQueueIsEmpty(obj)) { return false; } //不为空正常删除,front越界就调整回初始位置 ++obj->front; obj->front=obj->front%(obj->capacity+1); return true;}int myCircularQueueFront(MyCircularQueue* obj) { //为空就不能取到队首 if(myCircularQueueIsEmpty(obj)) { return -1; } //不为空就直接返回队首元素 return obj->arr[obj->front];}int myCircularQueueRear(MyCircularQueue* obj) { //为空就不能取到队尾 if(myCircularQueueIsEmpty(obj)) { return -1; } //不为空就直接返回队尾元素(prev,prev=rear-1),注意如果rear此时是越界后回到初始位置0的情况,特殊处理prev int prev=obj->rear-1; if(obj->rear==0) { prev=obj->capacity; } return obj->arr[prev];}void myCircularQueueFree(MyCircularQueue* obj) { if(obj->arr) free(obj->arr); free(obj); obj=NULL;}/** * 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刷题指南】--随机链表的复制
【LeetCode刷题指南】--有效的括号
【LeetCode刷题指南】--队列实现栈,栈实现队列
结语:本题的难度在力扣上属于中等难度的题,对于初学者来说会有点难,它的实现思路不是那么简单的,我们一定要通过画图加以理解。注意一些可能会出问题的地方,比如那几个需要特殊处理的情况,如果文章对你有帮助的话,欢迎评论,点赞,收藏加关注,感谢大家的支持。