设计循环队列 | C语言实现
以下是LeetCode原题链接:
https://leetcode.cn/problems/design-circular-queue/description/
https://leetcode.cn/problems/design-circular-queue/description/
思路
因为这个队列是循环利用的,所以开辟的空间大小是固定的,那么数据的增删可以靠下标的移动来完成而非开辟/释放空间,所以用数组实现队列是较为方便的。
该题较为困难的点是,如何区分满和空的情况。
可以多开辟一个空间,即k+1个空间来区分。
循环队列里需要包含头,尾和队列的大小,尾指向的是队尾元素的下一位。
假设队列大小是3,则开辟4个空间
空的情况

满的情况

以上就是解题思路,下面开始代码实现。
实现代码
创建循环队列指针
MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));//多开辟一个空间 k+1obj->a = (int*)malloc(sizeof(int)*(k+1));obj->front = obj->rear = 0;obj->k = k;return obj;
}
因为是需要返回创建的指针,所以要在堆上开辟,防止空间销毁。
空队列判定
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->front == obj->rear;
}
满队列判定
bool myCircularQueueIsFull(MyCircularQueue* obj) {return (obj->rear + 1) % (obj->k + 1) == obj->front;
}
当队列情况如下时,不能用obj->rear + 1 == front来判断。

这个时候可以让obj->rear + 1再对k+1取模。
比如rear的下标是3, (3+1) % 4 == 0,front的下标就是0。
这样就可以解决这种情况。
插入数据
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if (!myCircularQueueIsFull(obj)){obj->a[obj->rear] = value;obj->rear++;obj->rear %= obj->k + 1;return true;}elsereturn false;
}
插入前要判断是否满。
删除数据
注意:队列Push是头删
bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(!myCircularQueueIsEmpty(obj)){obj->front++;obj->front %= obj->k + 1;return true;}else{return false;}
}
因为是循环队列,所以要考虑到下述情况:

每次使obj->front %= ( k + 1)即可。
返回队头
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 - 1 + obj->k + 1) % (obj->k + 1)];
}
因为rear是队尾的下一个位置,所以返回队尾需要处理下述情况:

可以用(obj->rear - 1 + obj->k + 1) % (obj->k + 1)解决。
比如,rear是0,则 0 - 1 + 3 + 1 == 3,下标3就是队尾。
源码
typedef struct {int *a;int front;int rear;int k;
} MyCircularQueue;MyCircularQueue* myCircularQueueCreate(int k) {MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));obj->a = (int*)malloc(sizeof(int)*(k+1));obj->front = obj->rear = 0;obj->k = k;return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {return obj->front == obj->rear;
}bool myCircularQueueIsFull(MyCircularQueue* obj) {return (obj->rear + 1) % (obj->k + 1) == obj->front;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {if (!myCircularQueueIsFull(obj)){if (myCircularQueueIsEmpty(obj)){obj->a[obj->front] = value;}else{obj->a[obj->rear] = value;}obj->rear++;obj->rear %= obj->k + 1;return true;}elsereturn false;
}bool myCircularQueueDeQueue(MyCircularQueue* obj) {if(!myCircularQueueIsEmpty(obj)){obj->front++;obj->front %= obj->k + 1;return true;}else{return false;}
}int myCircularQueueFront(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;return obj->a[(obj->front + obj->k + 1) % (obj->k + 1)];
}int myCircularQueueRear(MyCircularQueue* obj) {if(myCircularQueueIsEmpty(obj))return -1;return obj->a[(obj->rear - 1 + obj->k + 1) % (obj->k + 1)];
}void myCircularQueueFree(MyCircularQueue* obj) {free(obj);
}/*** Your MyCircularQueue struct will be instantiated and called as such:* MyCircularQueue* obj = myCircularQueueCreate(k);* bool param_1 = myCircularQueueEnQueue(obj, value);* bool param_2 = myCircularQueueDeQueue(obj);* int param_3 = myCircularQueueFront(obj);* int param_4 = myCircularQueueRear(obj);* bool param_5 = myCircularQueueIsEmpty(obj);* bool param_6 = myCircularQueueIsFull(obj);* myCircularQueueFree(obj);
*/
