设计你的循环队列实现。 循环队列是一种线性数据结构,其操作表现基于 FIFO(先进先出)原则并且队尾被连接在队首之后以形成一个循环。它也被称为“环形缓冲器”。
循环队列的一个好处是我们可以利用这个队列之前用过的空间。在一个普通队列里,一旦一个队列满了,我们就不能插入下一个元素,即使在队列前面仍有空间。但是使用循环队列,我们能使用这些空间去存储新的值。
你的实现应该支持如下操作:
MyCircularQueue(k)
: 构造器,设置队列长度为 k 。Front
: 从队首获取元素。如果队列为空,返回 -1 。
Rear
: 获取队尾元素。如果队列为空,返回 -1 。enQueue(value)
: 向循环队列插入一个元素。如果成功插入则返回真。deQueue()
: 从循环队列中删除一个元素。如果成功删除则返回真。isEmpty()
: 检查循环队列是否为空。isFull()
: 检查循环队列是否已满。要求实现一个固定容量的循环队列,我们主要要思考一下问题
1.如何判断队空
2.如何判断队满
3.如何循环存放数据
如果使用单链表储存,那么数据访问比较麻烦,如果设定队尾指针指向队尾的下一个数据,用队头和队尾相等来判断队空,那么队满就不好判断,要么再引进一个size,要么就记录队尾的前一个,这些方法比较麻烦,如果设定队尾指向队尾元素,队尾和队头为空即队空,那么队满也是一个难题,
所以我们不妨使用数组来实现队列,我们设定队尾指针指向队尾的下一个
方法一:使用size计数,size为0即为空,size与队容量相等即为满,使用余数计算存放位置
方法二:多开一个空间,比如要求5个空间,我们开6个空间,那么队头等于队尾即为空,队头的上一个为队尾即为满,使用余数计算存放位置
typedef struct {
int *arr;
int front;
int back;
int size;
int k;
} MyCircularQueue;
我们使用一个size计数,arr为队列,front为队头,back为队尾,k为容量
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* q=( MyCircularQueue*)malloc(sizeof( MyCircularQueue));
q->arr=(int*)malloc(sizeof(int)*k);
q->front=0;
q->back=0;
q->size=0;
q->k=k;
return q;
}
分配空间,初始化值
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->size==0;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return obj->size==obj->k;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->arr[obj->back++]=value;
obj->back%=obj->k;
obj->size++;
return true;
}
如果队满即失败, obj->back%=obj->k,当队走到尾,如果队没有满,说明前面有空间,所以我们就取余数,让队尾循环到数组头,
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
obj->front++;
obj->front%=obj->k;
obj->size--;
return true;
}
如果队空即失败,obj->front%=obj->k,当队头走到尾,如果队列不为空,说明前面有数据,就让头循环回到数据头
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->arr[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
int a=(obj->back+obj->k-1)%obj->k;
return obj->arr[a];
}
在我们的设定中,队尾指向队尾的下一个,所以我们就会出现当队尾指针指向数组头时,队尾元素实际是在数组尾,使用(obj->back+obj->k-1)%obj->k来获取队尾,
typedef struct {
int *arr;
int front;
int back;
int size;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* q=( MyCircularQueue*)malloc(sizeof( MyCircularQueue));
q->arr=(int*)malloc(sizeof(int)*k);
q->front=0;
q->back=0;
q->size=0;
q->k=k;
return q;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->size==0;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return obj->size==obj->k;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->arr[obj->back++]=value;
obj->back%=obj->k;
obj->size++;
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
obj->front++;
obj->front%=obj->k;
obj->size--;
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->arr[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
int a=(obj->back+obj->k-1)%obj->k;
return obj->arr[a];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
}
typedef struct {
int *arr;
int front;
int back;
int k;
} MyCircularQueue;
这个方法更多使用取模运算
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* q=( MyCircularQueue*)malloc(sizeof( MyCircularQueue));
q->arr=(int*)malloc(sizeof(int)*(k+1));
q->front=0;
q->back=0;
q->k=k;
return q;
}
为了方便取模运算判断队空和队满,我们多开一个空间
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front==obj->back;
}
在这里,我们规定头等于尾为空
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->front-obj->back+obj->k)%(obj->k+1)==0;
}
我们规定尾等于头的上一个为满,所以我们让头减去尾再加上K,如果恰好为总容量+1,就为满,假设为满,那么头减去尾应该为1或-K,加上一个K即可判断
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->arr[obj->back++]=value;
obj->back%=(obj->k+1);
return true;
}
尾指向尾数据的下一个,我们多开了一个空间,所以循环时应该模K+1
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
obj->front++;
obj->front%=(obj->k+1);
return true;
}
同上,不过是改变头
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->arr[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
int a=(obj->back+obj->k)%(obj->k+1);
return obj->arr[a];
}
typedef struct {
int *arr;
int front;
int back;
int k;
} MyCircularQueue;
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* q=( MyCircularQueue*)malloc(sizeof( MyCircularQueue));
q->arr=(int*)malloc(sizeof(int)*(k+1));
q->front=0;
q->back=0;
q->k=k;
return q;
}
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front==obj->back;
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->front-obj->back+obj->k)%(obj->k+1)==0;
}
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj))
return false;
obj->arr[obj->back++]=value;
obj->back%=(obj->k+1);
return true;
}
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return false;
obj->front++;
obj->front%=(obj->k+1);
return true;
}
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
return obj->arr[obj->front];
}
int myCircularQueueRear(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj))
return -1;
int a=(obj->back+obj->k)%(obj->k+1);
return obj->arr[a];
}
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
}