力扣中的循环队列

力扣:622

循环队列的数组实现:

在这里插入图片描述
这里我们要思考的:
第一个问题:如何让其循环起来?
那当然是插入数据至尾时,改变尾下标使其重新指向头,从头开始
第二个问题:数据类型是说明?
首先肯定数组少不了,其次需要两个下标变量,一个表示头,一个表示尾;这时候有头有尾,还不知道数组长度,就需要一个k 来表示数组长度 ,因为方便传参到其他函数,直接对k进行访问

typedef struct {
    int *a;
    int front;
    int back;
    int k;
} MyCircularQueue;

第三个问题:数组开多大?k?k+1?(此处以k=5为例)

1.数组长度为k时:
在这里插入图片描述

开始时,front为0,因为front表示头的下标,开始队列为空,则back也为0,此时循环队列为空,判断为空的条件就是front是否等于back,然后插入一个数据,插入到back处,然后++back;
在这里插入图片描述
依次类推至最后:
在这里插入图片描述
此时back=front,数组属于满的情况;但是上边空也是这个判断条件,就会导致尴尬

2.数组长度为K+1时:
在这里插入图片描述
此时back在插入最后一个数据时,还未循环到头
就可以使用back+1与front的比较条件做为满的判断
因此第三个问题便解决了,开辟K+1的数组长度

这是循环队列的初始化

MyCircularQueue* myCircularQueueCreate(int k) {
    MyCircularQueue *obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));

    obj->a=(int*)malloc(sizeof(int)*(k + 1));
    obj->front=0;
    obj->back=0;
    obj->k=k;

    return obj;
}

下边是判断满和空:

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

//满的判断条件是back的下一个是front(back+1==front)
//但是不仅仅是这个,要考虑循环情况
bool myCircularQueueIsFull(MyCircularQueue* obj) {
	// 对(obj->back+1) 取% 针对的是满的情况,且back恰好是最后一个
	// 对于一般情况%(k+1)无影响,因为一个数%上比自己大的对自己无影响
    return ((obj->back+1)%(obj->k+1))==obj->front;
}

接下来是删数据和插数据

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
    //如果满就不能插入
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    else//不满则插入
    {
        obj->a[obj->back]=value;
        obj->back++;
        //考虑循环,让back重新回到头
        //举例为k=5:此时back++后,back为5+1=6;而k=5;k+1=6  6%6=0;等价于回到头
        obj->back %= obj->k+1;
        return true;
    }
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) {
    //为空,就不删,返回false
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    else
    {
        obj->front++;
        //同理,考虑头删没了,循环从数组起始处开始
        obj->front %= obj->k+1;
        return true;
    }
}

取队头队尾数据:

int myCircularQueueFront(MyCircularQueue* obj) {
     //为空,没有数据返回,题中要求 返回-1
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        return obj->a[obj->front];
    }
}

int myCircularQueueRear(MyCircularQueue* obj) {
    //为空,没有数据返回,题中要求 返回-1
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        //法一:
        //if(obj->back==0)
        //{
        //    return obj->a[obj->k];
        //}
        //else
        //{
        //    return obj->a[obj->back-1];
        //}

        //法二:找到尾下标,不分情况
        //+(k+1)给back=0准备的,%(k+1)给一般情况准备的
        return obj->a[(obj->back-1+obj->k+1)%(obj->k+1)];
    }
}

销毁:

void myCircularQueueFree(MyCircularQueue* obj) {
    //分两次释放,动态开辟的a数组以及循环队列
    free(obj->a);
    free(obj);
}

总结:

< 1 >循环队列与队列类似,只不过需要考虑back循环的判断;
< 2 >back %(数组长度)1.back小于数组长度时,无影响;2.back等于数组长度是,模完为0;即象征着回到头
< 3 >开辟数组时多开一个用于占位

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值