1.设计要求
设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
你的实现应该支持如下操作:
MyCircularQueue(k): 构造器,设置队列长度为 k 。
Front: 从队首获取元素。如果队列为空,返回 -1 。
Rear: 获取队尾元素。如果队列为空,返回 -1 。
enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真。
deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真。
isEmpty(): 检查循环队列是否为空。
isFull(): 检查循环队列是否已满。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/design-circular-queue
2.设计思路流程
1.我们先采用链表的方法实现,使链表的尾结点的指针指向头节点,这样就形成了一个循环链表,插入数据时插入到尾结点,采用尾插法。但是这样存在一个问题:空和满的条件是一样的,无法判断空还是满,此时判断条件都是head==tail。
2.上述方法不可取,我们空出来一个结点的方法,比如说有4个结点,但是我们只存储三个数据。判断空的条件还是head==tail,但是我修改判断满的条件为尾结点的下一个是头节点为满。插入数据我们依然采用尾插法。
3.以上方法均采用的是链表的形式,链表上在物理结果和逻辑结构上都是连续的,都是循环的,这使读者更加直观了解循环队列的实现。但是循环队列所存储的元素是一定的k个,不需要动态开辟内存空间,我们可以考虑采用顺序表来实现,顺序表在物理结构上并不连续,但是在逻辑结构上是连续的。
3.代码实现
typedef struct
{
int* a;
int k;//队列对多能存储多少数据
int front;//头
int tail;//尾(队尾数据下一个)
} MyCircularQueue;
(1)MyCircularQueue(k): 构造器,设置队列长度为 k
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* obj=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a=(int*)malloc(sizeof(int)*(k+1));
obj->front=0;
obj->tail=0;
obj->k=k;
return obj;
}
(2)Front: 从队首获取元素。如果队列为空,返回 -1
int myCircularQueueFront(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
return obj->a[obj->front];
}
}
(3)Rear: 获取队尾元素。如果队列为空,返回 -1
int myCircularQueueRear(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return -1;
}
else
{
int tailPrev=obj->tail-1;
if(tailPrev==-1)
{
tailPrev=obj->k;
}
return obj->a[tailPrev];
}
}
(4)enQueue(value): 向循环队列插入一个元素。如果成功插入则返回真
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if(myCircularQueueIsFull(obj))
{
return false;
}
else
{
obj->a[obj->tail]=value;
++obj->tail;
if(obj->tail==obj->k+1)
{
obj->tail=0;
}
}
return true;
}
(5)deQueue(): 从循环队列中删除一个元素。如果成功删除则返回真
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if(myCircularQueueIsEmpty(obj))
{
return false;
}
else
{
++obj->front;
if(obj->front==obj->k+1)
{
obj->front=0;
}
}
return true;
}
(6)isEmpty(): 检查循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->front==obj->tail;
}
(7)isFull(): 检查循环队列是否已满
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
int tailNext=obj->tail+1;
if(tailNext==obj->k+1)
{
tailNext=0;
}
return tailNext==obj->front;
}
(8)Free(): 销毁循环队列
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->a);
free(obj);
}