来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/design-circular-queue
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
【参考代码】
//采用顺序表
typedef struct {
int* a;
int front;
int rear;
int k;
} MyCircularQueue;
//声明
bool myCircularQueueIsEmpty(MyCircularQueue* obj) ;
bool myCircularQueueIsFull(MyCircularQueue* obj) ;
MyCircularQueue* myCircularQueueCreate(int k) {
//创建一个空队列
MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
cq->a = (int*)malloc(sizeof(int)*(k + 1));//注释一
cq->front = cq->rear = 0;//注释二
cq->k = k;
return cq;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
{
return false;
}
obj->a[obj->rear] = value; //注释三
++obj->rear;
obj->rear %= (obj->k + 1); //注释四
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return false;
}
++obj->front;
obj->front %= (obj->k + 1); //道理同注释四
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[obj->front]; //队头元素的下标值就是front的值
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
//找到真实数据队尾的下标
int i = (obj->rear + obj->k) % (obj->k + 1);
return obj->a[i];
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
//由于多开了一个空间,因此front和rear的值相等时该循环队列为空
return obj->front == obj->rear;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->rear + 1) % (obj->k + 1) == obj->front;
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}
【注释一】
顺序表实现的循环队列当front和rear指向同一块空间时队列可以为空也可以为满,因此单纯地看front和rear是无法判断队列是否满了。
判断循环队列满或空的其中几种方法:
- 制作一个计数器。
- 设置一个布尔变量。
- 多开一个空间。入队前先判断入队后尾指针是否等于头指针,如果相等则队满。
这里采用第三种,多开辟一个空间。cq->a = (int*)malloc(sizeof(int)*(k + 1));
【注释二】
要注意将front和rear初始化的数值,因为入一次数据后,rear才+1。
如果rear为0:
如果rear为-1,那么rear的值就是此时真实的队尾数据的下标。
【注释三】
要理解注释三,必须先理解注释二。
此时的rear这个下标的空间其实是队尾元素的下一个空间。因此直接将数值插入rear下标处,再将rear+1即可。
【注释四】
由于循环队列的长度在创建的时候就已经固定了。
obj->rear %= (obj->k + 1);
这样是为了实现循环。