设计循环队列

一.题目描述

设计循环队列_第1张图片

二.题目分析

设计循环队列_第2张图片

图中一共有八块空间,是否可以全部用来存储数据呢?

若数据为空,如图所示,front==rear;
若数据满了,如下图所示,front同样和rear一样,指向同一块空间

设计循环队列_第3张图片

如何区分呢??
第一种方法:假设一共有k+1个空间,其中k个空间用来存储数据,剩下一个空置,不用来存储,以便区分,队列满时:rear+1=front
第二方法:设置一个size记录元素个数,size==k+1时空间满了,size==0时为空。

这里我们采用第一种方法。

三.顺序表链表的选择

链表

设计循环队列_第4张图片

设计循环队列_第5张图片

设计循环队列_第6张图片

分析: 数据为空时:rear和front指向同一块空间。
    数据满时:rear->next==front.

设计循环队列_第7张图片

观察题目要求,发现最难搞得就是获取队尾元素
1.采用双向链表
2.增加一个指针,指向rear的前一个
3.遍历一遍找到对位数据

顺序表

设计循环队列_第8张图片

设计循环队列_第9张图片

设计循环队列_第10张图片

在这时候,7还没有插入,但是rear下标越界了,这是一个循环队列,要达到循环的效果,移动rear,如图所示。

设计循环队列_第11张图片

(rear+1)%(k+1)

设计循环队列_第12张图片

通过观察,两个下标之间相差6,也就是队列元素个数
rear+1=(rear+1)%(k+1)

正常情况下:队列满了,rear+1=front就满了,但是这个rear+1是经过(rear+1)%(k+1)转化过来
所以队列满:(rear+1)%(k+1)==front
队列空:rear==front

我们采用顺序表方式实现。

四.代码实现

//循环队列
typedef struct
{
    int*a;
    int k;
    int rear;
    int front;
} MyCircularQueue;

MyCircularQueue* myCircularQueueCreate(int k) 
{
     MyCircularQueue*obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
     //注意,这里的k个空间是用来存储元素的,以免产生分歧,创建k+1个
     obj->a=(int*)malloc(sizeof(int)*(k+1));
     obj->rear=obj->front=0;
     obj->k=k;
     return obj;
}
//题目中将以下两个函数接口放到了后面,但是在前面函数中要使用,
//函数要先声明后定义,放到前面就不用生命力,直接使用。
bool myCircularQueueIsEmpty(MyCircularQueue* obj) 
{
    return obj->rear==obj->front;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) 
{
    
        return   (obj->rear+1)%(obj->k+1)==obj->front;
}

bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) 
{
    if(myCircularQueueIsFull(obj))
    {
        return false;
    }
    obj->a[obj->rear]=value;
    obj->rear++;
    //rear走到最后的位置需要挪到前面去。
    obj->rear%=(obj->k+1);
    return true;
}

bool myCircularQueueDeQueue(MyCircularQueue* obj) 
{
    if(myCircularQueueIsEmpty(obj))
    {
        return false;
    }
    obj->front++;
     //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;
    }
    
    return obj->a[(obj->rear+obj->k)%(obj->k+1)];
}

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

在这里分析一下这段代码

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

设计循环队列_第13张图片

正常情况下取队尾数据就访问下标为rear-1的数据就可以。但是上面图是一个特例: rear-1就越界,而他的前一个为

设计循环队列_第14张图片

rear在这个位置,所以需要加上数据元素(rear-1+k+1)%(k+1) 化简为(rear+k)%(k+1)


容如有错误欢迎各位大神批评指正大家如果觉得有帮助的话点个赞支持一下博主喔✊✊后续还会继续更新其他的笔试题给到大家,如感兴趣可以多多关注一下博主

你可能感兴趣的:(数据结构,链表,数据结构,算法)