目录
1.首先粗略的了解一下队列
a.队列是一种数据结构,它遵循先进先出的规则(FIFO);
b..队列有队首(front)和队尾(rear);
c.队首出元素,队尾进元素,也就是说队首后移就是出元素,队尾后移就是进元素;
2.为什么要引进循环队列?
如图:
1.这种情况我们出一个元素front后移,再出一个元素再后移,此时如果我们要插入元素再插入元素就提示队满了;
2.但是front前面的两个空间没有被有效利用起来,这种情况我们称为"假溢出";为了解决这种情况我们如果可以把队尾rear再移动到1的位置继续插入就可以解决这种假溢出的问题~~
3.实现循环队列~~
为了可以更好的理解我们把队列这样表示:
a. 在这里我们要申请结构体来实现循环队列:
typedef struct {
int* arr;//存放数据
int front;//队首
int rear;//队尾
int count;//队内有效元素
int N;//循环队列的长度
} MyCircularQueue;
*考虑到判断循环队列满和空我们引进了count和N;
如果count=N则循环队列满;count=0则为空
b.创建循环队列:
MyCircularQueue* myCircularQueueCreate(int k) {
MyCircularQueue* q=(MyCircularQueue*)malloc(sizeof(MyCircularQueue));//申请空间
if(q==NULL){
return NULL;
}
q->arr=(int*)malloc(sizeof(int)*k);//申请空间
if(q->arr==NULL){
return NULL;
}
q->front=0;//初始化
q->rear=0;
q->count=0;
q->N=k;
return q;
}
这里我们申请k个空间来存放数组元素(队列元素);接下来对结构体内的变量进行初始化
c.接下来实现队列的判空和判满:
bool myCircularQueueIsEmpty(MyCircularQueue* obj) {//队列判空
if(obj->count==0){
return true;
}else{
return false;
}
}
bool myCircularQueueIsFull(MyCircularQueue* obj) {//队列判满
if(obj->count==obj->N){//对内有效元素与总容量相等则为满
return true;
}else{
return false;
}
}
-----很简单:1.count=0队列为空;
2.count=N队列为满
d.入循环队列
bool myCircularQueueEnQueue(MyCircularQueue* obj, int value) {
if(myCircularQueueIsFull(obj)){
return false;
}else{
obj->arr[obj->rear]=value;//没满赋值
obj->rear++;//队尾后移
obj->rear%=obj->N;//如果越界则重置
obj->count++;
}
return true;
}
1.首先判断队列是否为满-------为满不能入队;
2.不为满入队:首先队尾后移,若是下标最大为5,再入队rear++则为6,而我们想要的下标为0;此次我们可以进行%操作,则有obj->rear%=obj->N;不要忘了count++;
e.出队操作:
bool myCircularQueueDeQueue(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj)){//如果队列为空则返回
return false;
}else{
obj->front++;
obj->front%=obj->N;
obj->count--;
}
return true;
}
1.先判断队是否为空;为空返回
2.不为空我们进行出队:front++;和入队一样需要进行%-> obj->front%=obj->N
3.不要忘了count--;
f.返回队头:
int myCircularQueueFront(MyCircularQueue* obj) {
if(myCircularQueueIsEmpty(obj)){//判断队列是否为空
return -1;//为空返回-1
}else{
return obj->arr[obj->front];//不为空返回队首
}
}
1.如果队列为空不能返回0;因为0可能为有效元素,扰乱代码
2.否则返回队首front元素;
g.返回队尾:
int myCircularQueueRear(MyCircularQueue* obj) {
int N=obj->N;
if(myCircularQueueIsEmpty(obj)){//判断队列是否为空
return -1;//队列为空返回-1
}else{
return obj->arr[(obj->rear-1+N)%N];//返回队尾
}
}
1.如返回队首一样为空返回-1
2. 否则返回队尾:在这里队尾要返回rear-1,因为插入元素后rear后移;队尾为rear的前一个元素
3.如果rear刚好在下标为0的位置-1则为-1;下标越界了;在这里我们需要给rear+N则保证其不为负数;但又要保证数组右边不越界则需要再给其%N;则有------>return obj->arr[(obj->rear-1+N)%N]
h.循环队列的销毁:
void myCircularQueueFree(MyCircularQueue* obj) {
if(obj==NULL){//如果队列为空直接返回
return;
}
if(obj->arr){//先释放arr
free(obj->arr);
}
free(obj);//再释放obj
}
这里只需要注意一点:先释放数组空间在释放结构体空间~~
老铁们给个赞呗~~~~