目录
一、循环队列的特点:
二、普通的队列的缺点:
三、循环队列实现原理:
四、循环队列是实现步骤:
1.循环队列的头文件:
2.循环队列的源文件:
3.注意点:
一、循环队列的特点:
是具有队头指针和队尾指针,指示队列元素所在的位置,避免删除元素时移动大量元素。它只能队尾插入元素、在队头删除元素,是先进先出(First In First Out)的线性表,先进入的元素出队,后进入的元素才能出队。相比普通的队列,元素出队时无需移动大量元素,只需移动头指针。循环队列适合处理用户排队等待的情况,但需要预先分配大量存储空间。其时间复杂度为读取时O(1),插入、删除时O(1)。
循环队列的优点:防止假溢出!循环队列可以有效地利用空间,避免了普通队列在出队操作后无法再次利用已出队的空间的问题。此外,循环队列还可以通过修改指针的位置实现逆序输出。
二、普通的队列的缺点:
假溢出:前面的空间就无法利用。
三、循环队列实现原理:
是基于固定长度的数组实现。 并且会多开一个空间(区分满和空的情况)
循环队列是逻辑上循环,而不是物理上循环,物理上还是线性存储。
我们把第二个圈当做满来看,目的是为了用front和rear来区分空和满。
四、循环队列是实现步骤:
1.创建循环链表并且初始化
2.销毁循环队列
3.队列入,出4.判断队列是否为空
5.判断队列是否为满
6.输出队列内容(打印)
7.获取队列长度
8.获取队列头元素
9.获取队列尾元素
1.循环队列的头文件:
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>
typedef int CQDataType;
typedef struct CirQueue
{
CQDataType* a;//指向数组的首元素
int front;//指向头数据
int rear;//指向尾数据的下一个位置
int k;//实际存放的数据个数
}CQ;
//创建循环链表并且初始化
CQ* CreateQ(int n);
//销毁循环队列
void CirQueueDestry(CQ* cq);
//队列入,出
bool CirQueuePush(CQ* cq, CQDataType x);
bool CirQueuePop(CQ* cq);
//判断队列是否为空
bool CirQueueEmpty(CQ* cq);
//判断队列是否为满
bool CirQueueFull(CQ* cq);
//输出队列内容,打印
void CQPRINT(CQ* cq);
//获取队列长度
int CQSize(CQ* cq);
//获取队列头元素
CQDataType CQFrontElement(CQ* cq);
//获取队尾数据
int CirQueueRear(CQ* cq);
//销毁循环队列
void CirQueueDestroy(CQ* cq);
2.循环队列的源文件:
#define _CRT_SECURE_NO_WARNINGS 1
#include"CirQueue.h"
//创建循环链表并且初始化
CQ* CreateQ(int n)
{
CQ* cq = (CQ*)malloc(sizeof(CQ));
if (cq == NULL)
{
perror("malloc error");
exit(-1);
}
CQDataType* tmp = (CQDataType*)malloc(sizeof(CQDataType) * (n + 1));
if (tmp == NULL)
{
perror("malloc error");
exit(-1);
}
cq->a = tmp;
cq->front = cq->rear = 0;
cq->k = n;
return cq;
}
//销毁循环队列
void CirQueueDestry(CQ* cq)
{
free(cq->a);
free(cq);
}
//队列入,出
bool CirQueuePush(CQ* cq, CQDataType x)
{
if (CirQueueFull(cq))
{
return false;
}
cq->a[cq->rear] = x;
cq->rear++;
cq->rear %= (cq->k + 1);
return true;
}
bool CirQueuePop(CQ* cq)
{
if (CirQueueEmpty(cq))
{
return false;
}
cq->front++;
cq->front %= (cq->k + 1);
return true;
}
//判断队列是否为空
bool CirQueueEmpty(CQ* cq)
{
return cq->front == cq->rear;
}
//判断队列是否为满
bool CirQueueFull(CQ* cq)
{
return (cq->rear+1)%(cq->k+1) == cq->front;
}
//输出队列内容,打印
void CQPRINT(CQ* cq)
{
int szie = CQSize(cq);
if (cq->front > cq->rear)
{
for (int i = cq->front; i < cq->k+1; i++)
{
printf("%d ", cq->a[i]);
}
for (int i = 0; i < cq->rear; i++)
{
printf("%d ", cq->a[i]);
}
}
else
{
for (int i = cq->front; i < cq->rear; i++)
{
printf("%d ", cq->a[i]);
}
}
}
//获取队列长度
int CQSize(CQ* cq)
{
if (cq->front > cq->rear)
{
return (cq->k) - (cq->front) + (cq->rear)+1;
}
else
{
return (cq->rear) - (cq->front);
}
}
//获取队列头元素
CQDataType CQFrontElement(CQ* cq)
{
if (CirQueueEmpty(cq))
{
return -1;
}
return cq->a[cq->front];
}
//获取队尾元素
int CirQueueRear(CQ* cq)
{
if (CirQueueEmpty(cq))
{
return -1;
}
return cq->a[(cq->rear - 1 + cq->k + 1) % (cq->k + 1)];
}
3.注意点:
1.入队列:判断队列是否为满,满的时候就不能入队列
考虑rear++时越界,需要让它变成最小值。
2.出队列:判断队列是否为空
也要考虑front--时越界,也要考虑循环问题
3.判空:rear==front
4.判满:rear+1==front(也要考虑循环问题)