【手撕数据结构】循环队列

循环队列概念

我们前面已经介绍过队列,他的基本操作就是在队头出元素,在队尾如元素。今天介绍的循环队列与前面的队列有所不同,他可以一直利用申请的空间进行循环的出队列,入队列等操作。

结构分析

现在定义两个指针,一个指向队头,一个指向队尾
在这里插入图片描述
我们在front位置进行入队列。
在这里插入图片描述

队列初始化

typedef struct {
    int* arr;
    int front;  //队头
    int rear;   //队尾
    int capacity;   //存储空间个数
} MyCircularQueue;


这里我们不再用单链表作为队列的底层结构,而是采用数组来作为底层结构。原因是:循环队列需要重复利用一块空间地址而如果使用单链表作为底层结构,那么就不能直接释放头节点达到出队列的操作,那么再次使用这快空间要判断当前节点是否为空。而使用数组就可以直接移动front指针而不直接删除空间,如果需要重新利用删除的空间直接将front指针指向原来的空间,直接覆盖就行

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue* pst=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    pst->arr =(int*)malloc(sizeof(int)*(k+1));//多申请一块空间用于判断循环队列是否满了,且不为空
    pst->front=pst->rear=0;  //如果用front==reat判断队列满了,但是队列为空时也符合这个条件
    pst->capacity=k;  
    return pst;
}

这里我们需要多开辟一块空间,因为我们需要判断循环队列是否满了,这时候就有人说了,直接判断rear和front指针是否相等就行了啊.但是遗憾的是,我们队列为空的时候front也与rear相等。所以我们多开辟一块空间利用,(rear+1)%(capacity+1)这个表达式来判断

在这里插入图片描述

队列已满


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

上图已经解释

队列为空

bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
    return obj->rear == obj->front;
}

入队列

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //判断队列是否满了,满了不能插入数据
     if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    //队列没满
    obj->arr[obj->rear++]=value;
    obj->rear %= obj->capacity+1;       //这里就体现了多申请一块空间的好处,当是rear+1时%capacity+1就等于0,再插入数据就是1,例如:1%5还是为1,位置插入
    return true;
}

如果队列满了就不能再进行插入,没有满则再rear指针处插入数据

注意rear++的作用如:
在这里插入图片描述

出队列

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
   //队列为空
   if(myCircularQueueIsEmpty(obj))
   {
        return false;444
   }
   obj->front++;    //这里删除只需要++与栈删除只需要--一样的,因为是数组可以直接覆盖这个原来的元素,不需要像链表一样释放空间(因为链表物理结构不一定连续)
   //有可能front会越界,所以需要重新进循环
   obj->front %= obj->capacity+1;
   return true;
}

取队头元素

nt myCircularQueueFront(MyCircularQueue* obj) {
    //队列为空
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->arr[obj->front];
}

取队尾元素

int myCircularQueueRear(MyCircularQueue* obj) {
    //队列为空
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    int prev=obj->rear-1;
    if(obj->rear == 0)       //rear为0时,如果直接返回obj->[rear-1]会越界
    {
        prev=obj->capacity;
    }
    return obj->arr[prev];
}

在这里插入图片描述

销毁队列

void myCircularQueueFree(MyCircularQueue* obj) {
    free(obj->arr); //底层数组空间连续,所以只释放首地址
    free(obj);
    obj=NULL;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值