力扣题目分享:622.设计循环队列(C语言)

目录

题目:

剖析:

判断为满:

判断为空:

删除元素:

实战:

循环队列结构体(MyCircularQueue):

循环队列初始化(myCircularQueueCreate):

循环队列是否为空(myCircularQueueIsEmpty):

循环队列是否为满(myCircularQueueIsFull):

 循环队列插入元素(myCircularQueueEnQueue):

 循环队列删除元素(myCircularQueueDeQueue):

从队首获取元素(myCircularQueueFront):

从队尾获取元素(myCircularQueueRear):

 释放循环队列(myCircularQueueFree):

结果:


题目:

21b1e6da6fb24a25995a415de54131ab.png

理论来讲本题用数组和链表都可以,不过为了方便,这里就只说数组的方法。(C语言实现)

剖析:

我们可以先定义一个front(头)和rear(尾)(从0开始的下标),每插入一个元素就把rear往后一位(rear指向的是已有元素的下一个位置,也就是下一次插入元素的位置),每删除一个元素就把front往前一位,但如果直接直接定义k个元素的数组,就会出现下面这种情况

91f6c2bd63e7479ba507d2e52823353c.png

左边是一直插入元素,直到队列被插满,此时front==rear

右边是插入元素后开始删除元素,直到队列为空,此时front==rear

那么front==rear时到底是队列为满还是队列为空呢?


判断为满:

其实只要创建k+1个元素的数组,就能解决上述问题。

还是以上面k=4为例,那么数组就有5个元素,当rear的下一个就是front时,即为满,以下是几个满的例子:

804715c396c648c6a4b7a827062b29aa.png

第二和第三种情况还好说,只需要判断(rear+1)==front就行,但第一种rear+1不就成了5了?5!=0,还是会被判断成没满,我们来看下面的公式:

eq?%5Cleft%20%28%20rear+1%20%5Cright%20%29Mod%20%5Cleft%20%28%20k+1%20%5Cright%20%29%3D%3Dfront

rear的下一个位置模除数组的元素个数,这样即使rear超出了范围也会自动回到开头,我们将上面三个例子代入可得

(4+1)%(4+1)=0,front也为0,可判断为满

(0+1)%(4+1)=1,front也为1,可判断为满

(1+1)%(4+1)=2,front也为2,可判断为满


判断为空:

判断是否为空就简单了,也就是上面说的

eq?front%3D%3Drear

举个例子:

cc6914bb63ef46caa792d1748ba591fa.png

此时front删掉了最后一个元素,与rear相等,即为空。

空和满的循环队列逻辑图:

a7935d5e8ad6404db917b34c6102fa97.png


删除元素:

先来看以下两种删除元素的场景:

c90a6e0c6db94fa8b0a241af06bdd084.png

第二种情况删除元素时只需要front+1就可以,但第一种元素front+1就成了5,所以又要用到插入元素时的公式:

eq?front%3D%5Cleft%20%28%20front+1%20%5Cright%20%29Mod%20%5Cleft%20%28%20k+1%20%5Cright%20%29

front+1即为删除一个元素后front的值,此时再模除数组大小,这样即使超出范围也会自动回到开头,我们将上面两个例子代入可得

front=(4+1)%(4+1)=0,此时front走到了尽头,自动回到开头

front=(1+1)%(4+1)=2,此时front往前移一位,代表删除一个元素


实战:

循环队列结构体(MyCircularQueue):

_a负责存放数据,front是头下标,rear是尾指针,_k为创建的队列大小

typedef struct 
{
    int* _a;
    int _front;
    int _rear;
    int _k;
} MyCircularQueue;

循环队列初始化(myCircularQueueCreate):

这里qe和qe->_a都以malloc创建的原因是malloc创建的变量存在动态区,但普通的局部变量都在栈区,栈区的变量等函数体结束后就销毁了

MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* qe=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    qe->_a=(int*)malloc(sizeof(int)*(k+1));
    qe->_front=0;
    qe->_rear=0;
    qe->_k=k;
    return qe;
}

循环队列是否为空(myCircularQueueIsEmpty):

如上面所说,若rear和front相等,则为空,否则不为空

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->_rear==obj->_front;
}

循环队列是否为满(myCircularQueueIsFull):

这时就用到了上面提到的公式

eq?%5Cleft%20%28%20rear+1%20%5Cright%20%29Mod%20%5Cleft%20%28%20k+1%20%5Cright%20%29%3D%3Dfront

如果公式成立,则为满,否则为非满

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->_rear+1)%(obj->_k+1)==obj->_front;
}

 循环队列插入元素(myCircularQueueEnQueue):

这里复用了上面写的判断循环队列是否为满的函数,如果为满则无法插入,返回false,否则插入元素并返回真,

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    if(myCircularQueueIsFull(obj))
        return false;
    obj->_a[obj->_rear]=value;
    obj->_rear++;
    obj->_rear=obj->_rear%(obj->_k+1);//上面的公式
    return true;
}

 循环队列删除元素(myCircularQueueDeQueue):

这里复用了上面写的判断循环队列是否为空的函数,如果为空则无法删除,返回false,否则删除元素并返回true

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
        return false;
    obj->_front++;
    obj->_front=obj->_front%(obj->_k+1);//上面的公式
    return true;
}

从队首获取元素(myCircularQueueFront):

这里复用了上面写的判断是否为空的函数,按照题意,如果为空返回-1,否则返回队首的值

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->_a[obj->_front];
}

从队尾获取元素(myCircularQueueRear):

首先和上一个函数一样,是一个复用,用来判断是否为空,如果不是空,就返回队尾元素

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        int tail=obj->_rear-1;
        if(tail==-1)//如果rear在数组的0下标处,再减就会成-1,此时返回数组的最后一个位置的元素
            return obj->_a[obj->_k];
        return obj->_a[tail];
    }
}

 释放循环队列(myCircularQueueFree):

先释放_a再释放obj,否则如果先释放obj就找不到_a了

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

结果:

所以最终代码为:

typedef struct 
{
    int* _a;
    int _front;
    int _rear;
    int _k;
} MyCircularQueue;


MyCircularQueue* myCircularQueueCreate(int k) 
{
    MyCircularQueue* qe=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
    qe->_a=(int*)malloc(sizeof(int)*(k+1));//多开一个
    qe->_front=0;
    qe->_rear=0;
    qe->_k=k;
    return qe;
}

bool myCircularQueueIsFull(MyCircularQueue* obj);//在这声明是因为这两个函数在最下面,不声明的话找不到
bool myCircularQueueIsEmpty(MyCircularQueue* obj);

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

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

int myCircularQueueFront(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    return obj->_a[obj->_front];
}

int myCircularQueueRear(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return -1;
    }
    else
    {
        int tail=obj->_rear-1;
        if(tail==-1)//如果rear在数组的0下标处,再减就会成-1,此时返回数组的最后一个位置的元素
            return obj->_a[obj->_k];
        return obj->_a[tail];
    }
}

bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->_rear==obj->_front;
}

bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    return (obj->_rear+1)%(obj->_k+1)==obj->_front;
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值