LeetCode - 622. 设计循环队列(C语言,顺序存储结构,配图)
目录
编辑定义结构体:
1. MyCircularQueue(k): 构造器,设置队列长度为 k
2. Front: 从队首获取元素。如果队列为空,返回 -1
3. Rear: 获取队尾元素。如果队列为空,返回 -1
4. enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真
5. deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真
6. isEmpty(): 检查循环队列是否为空
7. isFull(): 检查循环队列是否已满
8. 扩展:如何判断队列有多少个元素?
622. 设计循环队列 - 力扣(LeetCode)
设计循环队列,我们可以从顺序结构和链式结构来考虑,但因为链式结构实现起来较为复杂,不易理解,且主流使用顺序存储,所以本文就是用顺序存储结构实现。
因为采用顺序存储结构,所以我们循环队列的元素空间是确定好的,为K+1个,这样可以保证总有一个空间是空的,方便我们接下来的判断。
定义结构体:
typedef struct {
int* a;
int front;
int rear;
int k;
} MyCircularQueue;
a:是存放数据的数组;
front:是头元素的下标;
rear: 是尾元素位置的下一个下标;
k: 是循环队列最多有多少个元素。
1. MyCircularQueue(k)
: 构造器,设置队列长度为 k
我们想要构造长度为N+1的顺序表来存储数据。
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a = (int*)malloc(sizeof(int)*(k+1));
obj->front =0;
obj->rear =0;
obj->k = k;
return obj;
}
2. Front
: 从队首获取元素。如果队列为空,返回 -1
这里我们需要注意,当我们在写题是,调用myCircularQueueIsEmpty时,一点要把这个函数放在Front函数之前定义,否则会报错。之后的韩束同理。
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[obj->front];
}
3. Rear
: 获取队尾元素。如果队列为空,返回 -1
写这个公式的原因是因为当rear==0时,我们需要单独判断,如果使用这个公式则不需要。
当rear-1!=-1且<k+1,那么+(k+1),在%不会有影响。如果==-1,+(k+1)后,变成最后一个数的下标。可以试着代数。
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[(obj->rear-1+obj->k+1)%(obj->k+1)];
}
4. enQueue(value)
: 向循环队列插入一个元素。如果成功插入则返回真
这里要注意的是,rear的变化,当rear++后,进行%,如果>k+1,%变成新的下标,否则不变。
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;
}
5. deQueue()
: 从循环队列中删除一个元素。如果成功删除则返回真
这里front与上面得rear同理。
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return false;
}
obj->front++;
obj->front = obj->front%(obj->k+1);
return true;
}
6. isEmpty()
: 检查循环队列是否为空
当rear == front时,循环队列为空。
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front == obj->rear;
}
7. isFull()
: 检查循环队列是否已满
这里判断,rear的下一个下标是不是front,如果是则循环队列已满。因为是循环,所以对rear进行%,确保不会越界。
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->rear+1)%(obj->k+1) == obj->front;
}
8. 扩展:如何判断队列有多少个元素?
如果正常情况,只需要 rear - front 就能得出有多少个元素。
当因为是循环队列,rear可能出现在front之前,这我们如何判断?
与Rear一样,我们总结出公式:元素个数 = (rear - front + k+1)% (k+1),这里k+1,就可以理解为将rear放到front之后。