当前位置:   article > 正文

设计循环队列(LeetCode:622.设计循环队列)_leetcode 循环队列

leetcode 循环队列

目录

写在前面的话:

一,题目分析

二,各接口实现

2.1构造循环队列

2.1.1两种不同形式的队列

2.1.2顺序表实现循环队列

2.2向队列中插入元素

2.3删除队列中元素

2.4获取队尾和队首元素

2.4.1获取队尾元素

2.4.2获取队首元素

2.4.3代码实现

2.5判空判满接口

2.5.1两种做法实现

2.5.2正确做法

2.5.3代码实现

 2.6释放队列

源码实现


写在前面的话:

小伙伴大家好啊!今天小编为大家带来一篇有关循环队列的题目。虽然说对于该题目,我们是将队列的接口直接拿过来用的,但是这个题目仍旧有一定的难度。

一,题目分析

如下图题目所示,循环队列首先基于先进先出,然后队尾连接在队首形成一个循环队列。它的优势表现在,如果队列链表满了之后,我们可以直接覆盖继续增加元素。

二,各接口实现

如下图所示,题目中要求有这些接口:

那么接下来,我们挨个实现。

2.1构造循环队列

2.1.1两种不同形式的队列

首先我们需要构造出一个空的循环队列。这里我们采用顺序表实现,当然也可以用链表实现,如下图所示: 

题目中要求,我们需要设置一个队列长度为 k 的一个循环队列。接下来我们的例子都以 k 为 4 来解题。 

那么我们发现,队列长度是 4 ,但是我们开辟了 5 个空间,这是因为如果后面在判断队列的空和满时,必须这样做,才能判断,否则将没法判断。那么这里我们暂时不关心这个,在后面我们会解释。

2.1.2顺序表实现循环队列

这里我们通过顺序表实现。首先,我们需要两个指针,一个 front 表示头,一个 tail 表示尾。一个数组 a,以及一个 k 表示当前队列的长度 。

  1. typedef struct {
  2. //数组实现
  3. int front;
  4. int tail;
  5. int k;
  6. int *a;
  7. } MyCircularQueue;
  8. MyCircularQueue* myCircularQueueCreate(int k) {
  9. MyCircularQueue*cq=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
  10. cq->front=0;
  11. cq->tail=0;
  12. cq->k=k;
  13. cq->a =(int*)malloc(sizeof(int)*(k+1));
  14. return cq;
  15. }

那么我们在构造队列时,需要注意的就是需要开辟 K+1 个空间,最后一个不能忘记的是将新开辟的空间返回。

2.2向队列中插入元素

首先,我们需要判断当前队列是否为满,如果当前队列为满的话,则直接返回false,否则进行插入操作。

如下代码所示,当队列不为空,然后进行插入操作时。首先我们将该元素插入尾指针 tail 表示的数组 a ,然后将尾指针自增 1 ,最后需要对 k 的值进行取模操作,因为这里表示的是循环队列,我们需要将其限制在一定的范围内。

而这里的取模也非常简单,就是将 tail 对 k+1 进行取模,但是需要注意这里只有 obj->k ,没有单独的 k 。 

2.3删除队列中元素

对于顺序表实现的队列来说,删除元素是比较简单的,但是我们需要删除的是队头的元素,因为队列的特性就是“先进先出”。所以这里我们判断完队列中不为空的时候,只需要将 front 自增 1即可,这也是我们数组中一般进行删除的方式。

当然 一定不能忘记的是对其取余,保证 front 限制在 队列长度的范围内。

2.4获取队尾和队首元素

那么对于获取队尾和队首元素,相对来说是比较简单的。但是这里需要注意的是,两个指针 front 和 tail 在每次删除或者插入元素之后,会自增。

以及题目中要求的。如果获取不到,则直接返回 -1。

2.4.1获取队尾元素

如下图所示,当前队尾元素是 tail 指针的前一个元素,所以这里我们需要对 tail 做一个修正之后才能得到队尾元素:(tail+k)%(k+1)

2.4.2获取队首元素

那么对于获取队首元素是相对比较简单的。直接返回当前 front 所在的元素即可。

2.4.3代码实现

两个接口的代码实现如下所示:

  1. int myCircularQueueFront(MyCircularQueue* obj) {
  2. if(myCircularQueueIsEmpty(obj))
  3. return -1;
  4. return obj->a[obj->front];
  5. }
  6. int myCircularQueueRear(MyCircularQueue* obj) {
  7. if(myCircularQueueIsEmpty(obj))
  8. return -1;
  9. //因为tail总是指向最后一个元素后面的空位置
  10. //所以需要找tail之前的那个位置上的元素
  11. int i=(obj->tail+obj->k)%(obj->k+1);
  12. return obj->a[i];
  13. }

2.5判空判满接口

2.5.1两种做法实现

如下图,我们可以看出,之前我们多开辟一个空间的作用就有了,如果我们没有多开辟一个空间,那么最开始没有数据的时候,以及数据满的时候,front 和 tail 指向的是同一个地方。

 

这样的表示方法,我们怎样去判断当前队列是否为空或者满呢?没法判断的,所以我们需要多开辟一个空间。

2.5.2正确做法

2.5.3代码实现

  1. bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
  2. return obj->front == obj->tail;
  3. }
  4. bool myCircularQueueIsFull(MyCircularQueue* obj) {
  5. return (obj->tail+1) % (obj->k+1) == obj->front;
  6. }

 2.6释放队列

开辟的两个指针,都需要释放哦!

源码实现

  1. typedef struct {
  2. //数组实现
  3. int front;
  4. int tail;
  5. int k;
  6. int *a;
  7. } MyCircularQueue;
  8. MyCircularQueue* myCircularQueueCreate(int k) {
  9. MyCircularQueue*cq=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
  10. cq->front=0;
  11. cq->tail=0;
  12. cq->k=k;
  13. cq->a =(int*)malloc(sizeof(int)*(k+1));
  14. return cq;
  15. }
  16. bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
  17. //如果为满,返回false
  18. if(myCircularQueueIsFull(obj))
  19. return false;
  20. //否则,添加元素,然后tail后移一位,如果超出数组范围,进行取模
  21. obj->a[obj->tail]=value;
  22. obj->tail++;
  23. obj->tail %= (obj->k+1);
  24. return true;
  25. }
  26. bool myCircularQueueDeQueue(MyCircularQueue* obj) {
  27. if(myCircularQueueIsEmpty(obj))
  28. return false;
  29. //有元素,删除
  30. //删除数组元素,不用free,只需要将其覆盖
  31. obj->front++;
  32. obj->front%=(obj->k+1);
  33. return true;
  34. }
  35. int myCircularQueueFront(MyCircularQueue* obj) {
  36. if(myCircularQueueIsEmpty(obj))
  37. return -1;
  38. return obj->a[obj->front];
  39. }
  40. int myCircularQueueRear(MyCircularQueue* obj) {
  41. if(myCircularQueueIsEmpty(obj))
  42. return -1;
  43. //因为tail总是指向最后一个元素后面的空位置
  44. //所以需要找tail之前的那个位置上的元素
  45. int i=(obj->tail+obj->k)%(obj->k+1);
  46. return obj->a[i];
  47. }
  48. bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
  49. return obj->front == obj->tail;
  50. }
  51. bool myCircularQueueIsFull(MyCircularQueue* obj) {
  52. return (obj->tail+1) % (obj->k+1) == obj->front;
  53. }
  54. void myCircularQueueFree(MyCircularQueue* obj) {
  55. free(obj->a);
  56. free(obj);
  57. }

好的,那么对于循环队列的题目就结束啦,如果小伙伴们有问题,可以留言评论哦! 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小蓝xlanll/article/detail/590133
推荐阅读
相关标签
  

闽ICP备14008679号