题目
思路
创建一个结构体变量维护一块数组空间,使用数组实现循环队列。
为了区分队列满和空:
方法1:存储k个数据时,开辟k+1个空间,始终空置一个空间不存放数据。
方法2:通过size统计队列中的元素个数。
代码实现
定义结构体
有了类型就知道变量的内存大小和该往内存中存放什么数据(如是结构体,就知道存放哪些成员)。
使用front、rear、k和a维护这块循环队列空间。
front指向队头元素。
rear指向队尾元素的下一个位置,也就是始终置空的位置。rear-1指向队尾元素。
k代表队列长度。
a存放数据的数组。
typedef struct
{
int front;
int rear;
int k;
int* a; //存放数据的数组
} MyCircularQueue;
创建结构体
为结构体申请内存和初始化成员。
检查是否为空
判断的标准就是front是否等于rear,如果等于返回true,否则返回false。
bool myCircularQueueIsEmpty(MyCircularQueue* obj)
{
return obj->front == obj->rear;
}
检查是否为满
判断的标准就是rear的下一个位置是front。
bool myCircularQueueIsFull(MyCircularQueue* obj)
{
//检查标准就是:rear的下一个位置就是front
return (obj->rear+1) % (obj->k+1) == obj->front;
}
插入元素
插入之前,检查队列是否为满。
实现插入的方式就是在下标rear的位置,填入数据。
但rear可能越过最大下标k(多开了1个空间),当rear等于k+1时,应该回到下标0的位置。
rear从6减小到0,通过求余实现。
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value)
{
//检查队列是否为满
if(myCircularQueueIsFull(obj))
{
return false;
}
//在rear位置插入元素
obj->a[obj->rear++] = value;
//避免越界
// obj->rear = (obj->rear) % (obj->k+1);
obj->rear %= (obj->k+1);
return true ;
}
删除元素
删除之前,检查队列是否为空。
实现删除的方式就是把下标front往左移动一个位置。
但front可能越过最大下标k(多开了1个空间),当front等于k+1时,应该回到下标0的位置。
front从6减小到0,通过求余实现。
bool myCircularQueueDeQueue(MyCircularQueue* obj)
{
//检查队列是否为空
if (myCircularQueueIsEmpty(obj))
{
return false;
}
obj->front++;
//避免越界
obj->front %= (obj->k+1);
return true;
}
获取队头元素
直接返回下标front的元素。
int myCircularQueueFront(MyCircularQueue* obj)
{
//检查队列是否为空
if (myCircularQueueIsEmpty(obj))
{
return -1;
}
return obj->a[obj->front];
}
返回队尾元素
方法1:创建双向链表。
方法2:增加一个rearPrev指针。
方法3:遍历获取队尾元素。
方法4:返回下标rear-1位置的元素。
但是rear等于0时,rear-1会越界,需要返回队尾下标k的位置。
rear从0增大到5,通过增大rear实现。
int myCircularQueueRear(MyCircularQueue* obj)
{
//检查队列是否为空
if (myCircularQueueIsEmpty(obj))
{
return -1;
}
// return obj->arr[obj->rear-1]; //可能越界
//使得rear-1不等于-1,而是回到下标5的位置
return (obj->rear + obj->k) % (obj->k+1);
}
释放内存
先释放堆数组,再释放结构体。
void myCircularQueueFree(MyCircularQueue* obj)
{
free(obj->arr);
free(obj);
}
申请了堆空间,在结束函数调用前,检查是否释放内存。
统一计算格式