描述
设计你的循环队列实现。循环队列是一种线性数据结构,
其操作表现基于FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
你的实现应该支持如下操作:
1、MyCircularQueue(k) :构造器, 设置队列长度为k。
方法:开辟k+1个数组空间,初始化循环队列。
2、Front:从队首获取元素。如果队列为空,返回-1。
方法:循环队列不为空,返回queue[front]。
3、Rear:获取队尾元素。如果队列为空,返回-1。
方法:循环队列不为空,如果tail等于0,返回queue[k],否则返回queue[tail-1]。
4、enQueue(value):向循环队列插入一个元素。如果成功插入则返回真。
方法:循环队列是否满,queue[tail]=x;tail++;修正循环队列的下标tail %= (k + 1);
5、deQueue() :从循环队列中删除一个元素。 如果成功删除则返回真。
方法:循环队列是否为空,front++;修正循环队列的下标front %= (k + 1);
6、isEmpty() :检查循环队列是否为空。
方法:front 等于 tail,返回真。
7、isFull() :检查循环队列是否已满。
方法:(tail+1) % (k+1) 等于 front,返回真。
循环队列的特性:1、符合先进先出 2、空间大小是固定的
思路:
循环队列,无论使用数组实现还是链表实现,都要多开一个空间。
1、如果是数组也就意味着,要是一个存k个数据的循环队列, 要开k + 1个空间否则无法实现判空和判满。
2、如果是链表也就意味着,要是一个存k个数据的循环队列, 要开k + 1个结点否则无法实现判空和判满。(链表结点必须开辟好)
因为初始时front == tail可以确定为空,但下一次当front == tail时到底是空还是满,有歧义。
循环队列,可以用数组实现,通过下标控制。也可以用链表实现,即循环链表。
1、当用数组实现时,下标front == tail表示空,(tail+1)%(K+1) == front表示满
2、当用链表实现时,指针front == tail表示空,tail->next == front表示满
1、MyCircularQueue* myCircularQueueCreate(int k);创建循环队列
typedef struct {
int* a;//利用指针维护的数组队列
int front;//队头下标
int tail;//队尾下标
int k;//队列容量
}MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k)
{
MyCircularQueue* cq = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
if (cq == NULL)
return NULL;
cq->a = (int*)malloc(sizeof(int) * (k + 1));//多开一个空间,区分空和满
cq->front = cq->tail = 0;
cq->k = k;
return cq;
//为什么不定义MyCircularQueue cq;再返回&cq。因为不能返回局部变量的地址。你也可以使用传址调用通过形参返回。
}
2、bool myCircularQueueEnQueue(MyCircularQueue* obj, int value);入队列
//入队列成功,返回真,没有成功(队列满了),返回假
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
if (myCircularQueueIsFull(obj))
{
return false;
}
obj->a[obj->tail] = value;//队尾入数据
++obj->tail;
obj->tail %= (obj->k + 1);//当插入的次数超过4次,也就是下标大于k,下标就需要重新回归
//注意:可以不需要if判断,没有超过k,obj->tail %= (obj->k + 1)仍为tail
return true;
}
3、bool myCircularQueueDeQueue(MyCircularQueue* obj);出队列
//出队列成功,返回真,没有成功(队列为空),返回假
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
if (myCircularQueueIsEmpty(obj))
{
return false;
}
++obj->front;//直接++,不遍历即可
obj->front %= (obj->k + 1);//当删除的次数超过4次,也就是下标大于k,下标就需要重新回归
//注意:可以不需要if判断
return true;
}
4、int myCircularQueueFront(MyCircularQueue* obj);获取队头元素
//当队列为空,返回-1。否则返回队头数据。
int myCircularQueueFront(MyCircularQueue* obj)
{
if (myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[obj->front];
}
5、int myCircularQueueRear(MyCircularQueue* obj);获取队尾元素
//当队列为空,返回-1。否则返回队尾数据。
int myCircularQueueRear(MyCircularQueue* obj)
{
if (myCircularQueueIsEmpty(obj))
{
return -1;
}
//注意:返回队尾下标的前一个数据
//方法1
/*
if (obj->tail == 0)//当队尾下标为0,则前一个数据是下标为k的值
{
return obj->a[obj->k];
}
else
{
return obj->a[obj->tail - 1];
}
*/
//方法2
int i = (obj->tail + obj->k) % (obj->k + 1);//获取真实下标
return obj->a[i];
}
6、bool myCircularQueueIsEmpty(MyCircularQueue* obj);判断循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->front == obj->tail;
}
7、bool myCircularQueueIsFull(MyCircularQueue* obj);判断循环队列是否为满
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
return (obj->tail + 1) % (obj->k + 1) == obj->front;
}
8、void myCircularQueueFree(MyCircularQueue* obj);销毁循环队列
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->a);
free(obj);
}
int main()
{
MyCircularQueue* cq = myCircularQueueCreate(4);
myCircularQueueEnQueue(cq, 1);
myCircularQueueEnQueue(cq, 2);
myCircularQueueEnQueue(cq, 3);
myCircularQueueEnQueue(cq, 4);
while (!myCircularQueueIsEmpty(cq))
{
int front = myCircularQueueFront(cq);
printf("%d ", front);
myCircularQueueDeQueue(cq);
}
myCircularQueueFree(cq);
return 0;
}
总结
循环队列,可以用数组实现,通过下标控制。也可以用链表实现,即循环链表。
1、当用数组实现时,下标front == tail表示空,(tail+1)%(K+1) == front表示满
2、当用链表实现时,指针front == tail表示空,tail->next == front表示满