1.题目要求
题目要求实现指定长度的循环列表,其队尾必须链接在队首之后,且要满足 FIFO(先进先出)原则。
2.基本思路
如果使用单向链表实现这道题,则会出现不好找尾的问题,删除尾之后,前一个指针就成了野指针,而且还会出现无法区分队列满或空的情况,在队列满和空的时候,头指针和尾指针都指向一个位置。
为了方便访问尾的前一个元素,本篇文章采用数组实现循环队列,为了使头和尾指针在列表满与列表空时区分开,在开辟数组时,选择多开一个位置,该位置不存储有效数据。
3.代码实现
typedef struct {
int* a;//数组实现队列
int k;//记录队列有效数据个数
int head;//头下标,指向队列的首元素
int tail;//尾下标,指向队列的尾元素的下一个
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->a = malloc(sizeof(int)*(k+1));//创建k+1长度的数组,最多存储k个有效数据
obj->head = obj->tail = 0;
obj->k = k;
return obj;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
//如果头和尾的值相同,说明队列为空
if(obj->head == obj->tail)
return true;
else
return false;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
//记录tail的下一个数据
int next = obj->tail+1;
//如果tail下一个值为k+1,说明tail已经在数组边界上,下一步next是0而不是tail+1
if(next == obj->k+1)
{
next = 0;
}
//如果tail的下一个值就是head,说明已满
if(next == obj->head)
return true;
else
return false;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
//检查队列是否已满
if(myCircularQueueIsFull (obj))
return false;
//将数据尾插到tail上,更新tail
obj->a[obj->tail] = value;
obj->tail++;
//如果尾的值为k+1,说明已经超出数组边界,需要回到下标0的位置
if(obj->tail == obj->k+1)
obj->tail=0;
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
//判断队列是否为空
if(myCircularQueueIsEmpty(obj))
return false;
//队头出数据,头指针往后走一步
obj->head++;
//如果头的值为k+1,说明已经超出数组边界,需要回到下标0的位置
if(obj->head == obj->k+1)
obj->head=0;
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
//判断队列是否为空
if(myCircularQueueIsEmpty(obj))
return -1;
//返回数组head位置的数据
return obj->a[obj->head];
}
int myCircularQueueRear(MyCircularQueue* obj) {
//判断队列是否为空
if(myCircularQueueIsEmpty(obj))
return -1;
//记录尾的前一个
int prev = obj->tail-1;
//如果tail在位置0,则前一个位置在k处而不是-1
if(obj->tail == 0)
prev = obj->k;
return obj->a[prev];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->a);
free(obj);
}