设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k)
: 构造器,设置队列长度为 k 。
Front
: 从队首获取元素。如果队列为空,返回 -1 。
Rear
: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value)
: 向循环队列插入一个元素。如果成功插入则返回真。
deQueue()
: 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty()
: 检查循环队列是否为空。
isFull()
: 检查循环队列是否已满。
实现方法
(1)循环队列的基本结构
(2)循环队列的创建
在这段代码中,为什么我们再给数组a申请空间的时候需要e外多申请一个空间呢?
我们首先来看不申请额外空间的操作,假设k为4,我们在其中加入3个元素
这时我们再删去三个元素,也就是把循环队列置为空,得到队列为空的条件是head==tail
那如果我们再次插入四个元素,使循环队列成为满队列会发生什么呢?
没错,我们发现tail还是等于head,为了避免混淆,我们采用了创建一个额外空间的方法
空的条件还是head==tail,满的条件则是(tail+1)%(k+1)== head
完整代码如下:
typedef struct {
int*a;//用数组实现循环队列
int head;//数组的头
int tail;//数组的尾(注意指向的是尾部元素的下一个)
int k;//规定数组的大小
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue*pq=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
pq->a=(int*)malloc(sizeof(int)*(k+1));//创建额外空间
pq->head=pq->tail=0;
pq->k=k;
return pq;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->head==obj->tail;//空的条件
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->tail+1)%(obj->k+1)==obj->head;//满的条件
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))//先判断队列是否已经满了
return false;
obj->a[obj->tail++]=value;
obj->tail%=(obj->k+1);//tail向后走并取模,避免越界
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))//先判断队列是否为空
return false;
obj->head++;
obj->head%=(obj->k+1);//head向后走并取模,避免越界
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
else
return obj->a[obj->head];//本质为返回head指向的元素
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
else
return (obj->tail==0)?obj->a[obj->k]:obj->a[obj->tail-1];//当tail为0时,尾元素为数组尾部元素,其余的则是tail-1所指向的元素
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
obj->a=NULL;
obj->head=obj->tail=obj->k=0;
}
/**
* 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);
*/