接口及要求
开始错误的逻辑
看到队列,首先我就想到了用链表来实现,但是这道题实际上用数组实现比较好一点,题目中提到循环,说明他是定长的一个队列,且要重复利用队列之前的空间存储新值。
rear++,始终要指向当前元素的下一个用于插入数据
与前面对比,当队列数据满了front 和rear也是相等的,那么到底是队列为空front与rear相等,还是队列满元素两者相等?这只是两个例子,还有很多的测试用例可以证明,因为无法区分两种情况,说明这样的循环队列结构已经出现问题.
修改思路
所以我们让队列多开一个空间,让这个位置永远空出来(并不需要一直是最后一个位置空)用于判断队列满和空。
当rear+1等于front时,队列满。怎 么实现呢?
假设现在数组大小是k,只需要rear的下标%k,就能得到自己的下标,队列要满front永远在rear的前一个所以(rear+1)%k就能得到front的值,人家题目给的数组大小是k,我们要多开一个空间,所以数组大小为k+1,所以front下标的位置就是(rear+1)%(k+1),所以判断条件就是(rear+1)%(k+1)==front`
空的位置是任意的,与场景有关:
当front等于rear时队列为空(front++,删除数据)
代码
然后开始写代码即可,但是要注意各种边界问题,尤其是头和尾
typedef struct {
int* _a;
int _front;
int _rear;
int _k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
//假如这里 MyCircularQueue* q;然后初始化q,返回q是错误的。因为出函数q所指向的地址被free掉,外面接收了q,还在指人家的地址,悬空指针
//必须malloc
MyCircularQueue* q=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
//多开一个
q->_a=(int*)malloc(sizeof(int)*(k+1));
q->_front=0;
q->_rear=0;
q->_k=k;
return q;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
//满了就不插
if(myCircularQueueIsFull(obj))
{
return false;
}
obj->_a[obj->_rear]=value;
//假设数组4个元素,大小为4+1,到了数组末尾下标为4,
obj->_rear++;
//不越界:就是自身的位置,越界:数组一越界就把他放到数组头(4++后5,5%5=0,)
obj->_rear%=obj->_k+1;
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
//空就不删
if(myCircularQueueIsEmpty(obj))
{
return false;
}
obj->_front++;
//和插入的时候%k+是一样的意思
obj->_front%=obj->_k+1;
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
return obj->_a[obj->_front];
}
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
int tail=obj->_rear-1;
//当rear为0时减1变成-1,这种情况我们单独做个判断
if(tail==-1)
{
tail=obj->_k;
}
return obj->_a[tail];
}
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
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);
}
/**
* 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);
*/