leetcode经典例题之环形队列

P. S.:以下代码均在VS2019环境下测试,不代表所有编译器均可通过。
P. S.:测试代码均未展示头文件stdio.h的声明,使用时请自行添加。

  

1、题目展示

在这里插入图片描述


  在拿到题目时,通过分析我们知道,环形队列是一个有用固定位置数的队列,若队列已满就不能再向其中插入数据,且队列为循环,及队列的尾部的下一个为队列的头部。
  在这种前提条件下,我们会联想到可以使用链表的形式进行实现,但是在使用链表创建队列时,需要开辟出题目要求数量的节点,并将其连接起来,十分麻烦,且在进行删除插入操作时会有对指针的操作,容易出现bug,故本文仅对如何使用数组来实现循环队列进行讲解。


2、问题分析


  当使用数组来实现队列时,我们可以先假设题目要求创建四个空间存储空间的循环队列,示意图如下:

在这里插入图片描述  在创建好数组之后我们又如何让其可以循环呢,可以思考,当指向下标的位置越过了数组限制下标3时,我们让他取模,并回归到数组的0下标,或者也可以设置一个size来记录数组内数据的个数,并通过size来进行循环。


  可循环的问题解决了,那我们如何判断循环队列中的空间是否满了或者空呢,我们可以设置两个数分别为head和tail,让其指向数组的首元素下标,即开始时head和tail都为0,当head和tail相等时,就判断它时空的循环队列。
  可这时问题又出现了,当我们队列里存满了数据时,head也和tail相等,这就造成了很明显的bug,无法判断是相等还是空,这时我们可以在创建数组时多创建一个空间,比如说我们需要四个空间,在创建时就创建五个空间,但是数组里最多只存储四个数据,即总有一个空间是不存储数据的,这样就完美的解决了假溢出的问题。示意图如下:

在这里插入图片描述

  此时我们假设进行两步操作,第一次向循环队列中插入四个数据,第二次删除四个数据。示意图分别如下:
在这里插入图片描述
在这里插入图片描述


  我们可以明显地发现当tail的下一个位置为head时,循环队列时满的状态,当tail等于head时,循环队列是空的状态。
  至此我们便可以依据此种规律进行代码的书写。


3、完整代码展示


  至于如何对越界的head和tail进行取模转换,是一个数学上的问题,再此不再做过多的详解,看官可通过数学知识自行解答,下面是完整代码展示:
typedef struct 
{
    int* a;
    int head;
    int tail;
    int k;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    obj->a = (int*)malloc(sizeof(int)*(k+1));
    obj->head = 0;
    obj->tail = 0;
    obj->k = k;
    return obj;
}

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

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

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

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

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

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


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




4、结语


  十分感谢您观看我的原创文章。
  本文主要用于个人学习和知识分享,学习路漫漫,如有错误,感谢指正。
  如需引用,注明地址。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值