前几天,在力扣做了一个很有意思的编程题(力扣链接),今天我就将它分享给大家,并向大家讲解其中一个解题思路,希望能够有点帮助。
题目要求
循环队列相比普通队列,有一个难点:判满和判空。
front为队首,back为队尾。如上图(队列为空),front == baack;
插入一个元素之后,back++,为满时,back就又会等于front,以此就没法判断了。
于是接下来,有两种解决方法:
1.加上一个变量size, size==数组长度时为满,size==0时为空。
2.开头创建的数组长度为k+1,能有效存储的数据个数为k,当back+1==front时为满,back==front为 空。
那么,接下来就使用第二种方法(如果使用链表实现循环队列的话建议使用第一种)
一.基本结构体
typedef struct {
int* arr;//数组实现
int front;//队首
int back;//队尾
int n;//数组长度
} MyCircularQueue;
二.构造器
//构造器
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->arr = (int*)malloc(sizeof(int) * (k + 1));
//初始化
obj->front = obj->back = 0;
obj->n = k + 1;//上文提到的数组长度为K+1,储存的数据个数为K
return obj;
}
三.检查队列是否为空
//检查循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front == obj->back;
}
四.检查循环队列是否已满
//检查循环队列是否已满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->back + 1) % (obj->n) == obj->front;
}
注意,这里(back+1)% n是控制back如果到达空间尾时,back回到0位置.(如图,此时back==4,back+1==5就会越界,当(back+1)%n就等于0,(n==K+1==5) , 会回到0位置,实现循环).
五.向循环队列插入一个元素
//向循环队列插入一个元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if (myCircularQueueIsFull(obj))
{
return false;
}
obj->arr[obj->back] = value;
obj->back++;
//控制如果到达空间尾时,back回到0位置
obj->back %= obj->n;
return true;
}
六.从循环队列中删除一个元素
//从循环队列中删除一个元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if (myCircularQueueIsEmpty(obj))
{
return false;
}
obj->front++;
//控制如果到达空间尾时,front回到0位置
obj->front %= obj->n;
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;
}
return obj->arr[(obj->back - 1 + obj->n) % obj->n];
}
此时就又出现了一个坑,不少人会粗心,直接return obj->arr[obj->back-1];
因为我们并没有考虑到back==0的情况。
当然,如果直接加一个判断obj->back==0时,return obj->arr[obj->n-1];也是一种方法。
而一种更取巧的方法就是(back-1+n)%n.
代入0来看,(0-1+5)% 5 == 4. (k=4,n=k+1) 没问题
代入3来看,(3-1+5) %5 == 2 没问题
...............
九.销毁
//销毁
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
}
以上就是全部内容了,欢迎大家斧正哦。
源码:
typedef struct {
int* arr;//数组实现
int front;//队首
int back;//队尾
int n;//数组长度
} MyCircularQueue;
//构造器
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* obj = (MyCircularQueue*)malloc(sizeof(MyCircularQueue));
obj->arr = (int*)malloc(sizeof(int) * (k + 1));
//初始化
obj->front = obj->back = 0;
obj->n = k + 1;
return obj;
}
//检查循环队列是否为空
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {
return obj->front == obj->back;
}
//检查循环队列是否已满
bool myCircularQueueIsFull(MyCircularQueue* obj) {
return (obj->back + 1) % (obj->n) == obj->front;
}
//向循环队列插入一个元素
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if (myCircularQueueIsFull(obj))
{
return false;
}
obj->arr[obj->back] = value;
obj->back++;
//控制如果到达空间尾时,back回到0位置
obj->back %= obj->n;
return true;
}
//从循环队列中删除一个元素
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if (myCircularQueueIsEmpty(obj))
{
return false;
}
obj->front++;
//控制如果到达空间尾时,front回到0位置
obj->front %= obj->n;
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;
}
return obj->arr[(obj->back - 1 + obj->n) % obj->n];
}
//销毁
void myCircularQueueFree(MyCircularQueue* obj) {
free(obj->arr);
free(obj);
}