题目
题目链接:622. 设计循环队列
思路
设计循环队列有两种实现方式
第一种是使用数组实现;
第二种是使用单链表实现;
而设计循环队列不管是使用数组实现还是使用单链表实现,都需要给数组预留出一个空间,目的是为了判断队列是否满和是否为空!
第一种是使用数组实现:
判断满的条件:(tail + 1) %size == front
,其中 tail表示队尾,front表示对头,size表示数组大小;
判断为空的条件:tail == front
;
由于是循环队列:所以在插入删除数据的时候,就不可以简单的是数组下标加一了,还需要模上数组的大小:
尾插(入队),tail移动的方式:(tail+1) % size
;
头删(出队),front移动的方式:(front+1) % size
;
实现代码:
//数组设计循环队列
//设计循环队列的重要:要开辟比给定的数组大小,开辟多一个空间:为的是实现判空和判满
typedef struct {
int* a; //数组
int front;
int tail;
int k; //队列容量大小
} MyCircularQueue;
bool myCircularQueueIsEmpty(MyCircularQueue* obj);
bool myCircularQueueIsFull(MyCircularQueue* obj);
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* cQ = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
//开辟多一个空间目的是为了预留空间,判空判满
//初始化设计的队列
cQ->a =(int*)malloc(sizeof(int)*(k+1));
cQ->front = 0;
cQ-> tail = 0;
cQ->k = k;
return cQ;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->a[obj->tail] = value;
//tail移动一位,但是由于是循环的,需要控制下标不越界
//控制手段就是模上数组的空间大小,即可这里数组空间大小为k+1;
obj->tail = (obj->tail +1) %(obj->k+1);
//下面的方式也可以控制下标,只是写法不一样,和上面的控制下标方式等价
//++obj->tail;
//obj->tail %=(obj->k+1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
//++obj->front;
//obj->front %=(obj->k+1);
//控制下标的移动
obj->front = (obj->front+1) %(obj->k+1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->a[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
//由于tail指向的位置是最后一个数据的下一个位置
//所以获取队尾元素需要 得到tail-1的位置
//由于是循环队列,所以要控制tail不能越界为-1
//即 下标 = (tail-1 +size ) % size
return obj->a[(obj->tail - 1 +(obj->k + 1)) %(obj->k+1)];
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
//判空条件
return obj->front == obj->tail;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
//判满条件
return (obj->tail +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);
*/