队列遵循“先进先出”的原则,也被成为 FIFO”结构
数据结构中的队列的两端都允许操作,只不过要求数据只能从队列的一端插入,从队列的另一端删除,可以把队列理解为一根水管,水管有进水口和出水口。一般把允许数据插入的端称为队尾(Tail或者Rear)。一般把允许删除数据的一端称为队头(Head 或者Fron)尾插:enqueue 头删:dequeue
循环队列:
- 判断空队的条件:队尾下标等于队首下标
- 判断满队的条件:(队尾下标+1) %容量=队首下标 –>空间换时间的案例
- 入队需要判断:当前队是否为满的
- 出队需要判段:当前队是否为空的
/******************************************************************************
*
* file name : Structure equence
* author : Wzy
* data : 2025/12/10
* function : 实现循环队列
* note : None
*
* copyRight (c) 2025 17630246607@163.com All Right Reseverd
* ****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
//指的是循环队列中的元素的数据类型,用户可以根据需要进行修改
typedef int DataType_t;
//构造记录循环队列CircularQuence各项参数,(循环队列的首地址+循环队列的容量+循环队列队尾下标+队首下标)
typedef struct CircularQuence
{
DataType_t *Addr; //记录循环队列首元素地址
unsigned int Size; //记录循环队列元素的容量
int Rear; //记录循环队列队尾下标
int Front; //记录循环队列队首下标
}CirQuence_t;
/******************************************************************************
*
* func name : CirQuence_Create
* function : 创建并初始化循环队列
* argument :
* @size:指定循环队列的初始总容量
* retval : 返回初始化后的Manager指针
* author : Wzy
* date : 2025/12/10
* note : None
*
* ****************************************************************************/
//1.创建循环队列并对循环队列进行初始化
CirQuence_t * CirQuence_Create(unsigned int size)
{
//利用calloc为循环队列的管理结构体申请一块堆内存
CirQuence_t *Manager = (CirQuence_t *)calloc(1,sizeof(CirQuence_t));
if(NULL == Manager)
{
perror("calloc memory for manager is failed");
exit(-1); //程序异常终止
}
//2.利用calloc为所有元素申请堆内存,,并完成错误处理
Manager->Addr =(DataType_t *)calloc(size,sizeof(DataType_t));
if(NULL == Manager->Addr)
{
perror("calloc memory for element is failed");
free(Manager);
exit(-1); //程序异常终止
}
//3.对管理循环队列的结构体进行初始化(循环队列容量 + 队尾下标 + 队首下标)
Manager->Size = size; //对循环队列容量进行初始化
Manager->Front = 0; //由于循环队列为空,则队首下标初值为0
Manager->Rear = 0; //由于循环队列为空,则队尾下标初值为0
return Manager;
}
/******************************************************************************
*
* func name : CirQuence_IsFull
* function : 判断循环队列是否已满
* argument :
* @CirQuence *Manager是管理循环队列的结构体的地址
* retval : bool flag :bool型返回值,如果循环队列已满,返回true。没满返回false
* author : Wzy
* date : 2025/12/10
* note : 这个函数是为了后面在循环队列增加元素,如果循环队列满了,就不能在向当前的循环队列中增加元素
*
* ****************************************************************************/
bool CirQuence_IsFull(CirQuence_t *Manager)
{
return ( (Manager->Rear + 1) % Manager->Size == Manager->Front) ? true : false; //循环队列判断满队的条件:(队尾下标+1) %容量 =队首下标 -->空间换时间的案例
}
/******************************************************************************
*
* func name : CirQuence_Enquence
* function : 向循环队列尾部中加入元素
* argument :
* @SeqList_t *Manager是管理顺序表的结构体的地址
* @DataType_t Data:Data是要增加在顺序表中的元素。DataType_t是增加在顺序表中的元素的类型,即元素Data的类型是DataType_t
* retval : false:循环队列已满,无法在循环队列中增加元素
* true :循环队列未满,已经在循环队列尾部增加了新元素
* author : Wzy
* date : 2025/12/10
* note : None
*
* ****************************************************************************/
//入队
bool CirQuence_Enquence(CirQuence_t *Manager,DataType_t Data) //CirQuence_t *Manager是管理循环队列的结构体的地址,Data是循环队列中的元素。DataType_t是循环队列中的元素的类型
{
// 1.判断循环队列是否已满
if (CirQuence_IsFull(Manager))
{
printf("CirQuence is Full!\n");
return false;
}
//2.如果循环队列有空闲空间,则把新元素增加到循环队列尾部
Manager->Addr[Manager->Rear] = Data;
//防止队尾下标越界
Manager->Rear = (Manager->Rear + 1) % Manager->Size;
return true;
}
/******************************************************************************
*
* func name : CirQuence_IsEmpty
* function : 判断循环队列是否是空的
* argument :
* @CirQuence_t *Manager是管理循环队列的结构体的地址
* retval : bool :bool型返回值,如果循环队列是空的,返回true。不是空的返回false
* author : Wzy
* date : 2025/12/04
* note : 这个函数是为了后面删除循环队列中的元素,如果循环队列是空的,就不能在向当前的循环队列中删除元素
*
* ****************************************************************************/
bool CirQuence_IsEmpty(CirQuence_t *Manager)
{
return (Manager->Front == Manager->Rear) ? true : false; // 判断空队的条件:队尾下标等于队首下标
}
/******************************************************************************
*
* func name : CirQuence_Dequence
* function : 删除循环队列中的尾部元素。
* argument :
* @SeqList_t *Manager是管理循环队列的结构体的地址
* retval : bool :bool型返回值,如果删除成功,返回true。删除失败返回false
* author : Wzy
* date : 2025/12/10
* note : None
*
* ****************************************************************************/
//出队
DataType_t CirQuence_Dequence(CirQuence_t *Manager)
{
DataType_t temp = 0; //接收出队的元素
//1.调用CirQuence_IsEmpty函数判断当前循环队列是否为空
if(CirQuence_IsEmpty(Manager))
{
printf("CirculareQuence is Empty!\n");
return false;
}
//2.把元素从队首出队,并且备份到temp中
temp = Manager->Addr[Manager->Front];
//防止队首下标越界
Manager->Front = (Manager->Front + 1) % Manager->Size;
return temp;
}
/******************************************************************************
*
* func name : CirQuence_Print
* function : 遍历循环队列中的元素
* argument :
* @CirQuencet_t *Manager是管理循环队列的结构体的地址
* retval : None
* author : Wzy
* date : 2025/12/10
* note : None
*
* ****************************************************************************/
void CirQuence_Print(CirQuence_t *Manager)
{
// 1.判断循环队列是否为空
if (CirQuence_IsEmpty(Manager))
{
printf("CircularQuence is Empty! No elements to print.\n");
return;
}
// 2.遍历循环队列(从队首到队尾)
printf("CircularQuence elements: \n");
int i = Manager->Front; // 从队首开始遍历
while (i != Manager->Rear) // 遍历到队尾结束
{
printf("%d ", Manager->Addr[i]);
i = (i + 1) % Manager->Size; // 防止下标越界
}
printf("\n");
}
int main(int argc, char const *argv[])
{
// 1.创建容量为5的循环队列(实际可用容量为4,因预留一个空位判满)
CirQuence_t *queue = CirQuence_Create(5);
if (NULL == queue)
{
printf("Create CircularQuence failed!\n");
return -1;
}
printf("Create CircularQuence success, size: %u\n", queue->Size);
// 2.入队操作:添加4个元素(达到最大可用容量)
printf("\n=== Enquence Test ===\n");
CirQuence_Enquence(queue, 10);
CirQuence_Enquence(queue, 20);
CirQuence_Enquence(queue, 30);
CirQuence_Enquence(queue, 40);
CirQuence_Print(queue); // 打印:10 20 30 40
// 3.测试队列满:尝试入队第5个元素
printf("\n=== Test Full Queue ===\n");
if (!CirQuence_Enquence(queue, 50))
{
printf("Enquence 50 failed (queue full)\n");
}
CirQuence_Print(queue); // 打印结果不变
// 4.出队操作:依次出队2个元素
printf("\n=== Dequence Test ===\n");
DataType_t data = CirQuence_Dequence(queue);
printf("Dequence element: %d\n", data); // 10
data = CirQuence_Dequence(queue);
printf("Dequence element: %d\n", data); // 20
CirQuence_Print(queue); // 打印:30 40
// 5.再次入队:验证循环特性
printf("\n=== Enquence Again (Circular Test) ===\n");
CirQuence_Enquence(queue, 50);
CirQuence_Enquence(queue, 60);
CirQuence_Print(queue); // 打印:30 40 50 60
// 6.清空队列:测试判空
printf("\n=== Clear Queue Test ===\n");
while (!CirQuence_IsEmpty(queue))
{
data = CirQuence_Dequence(queue);
printf("Dequence element: %d\n", data);
}
CirQuence_Print(queue); // 打印空队列提示
// 7.测试空队列出队
printf("\n=== Test Empty Queue ===\n");
data = CirQuence_Dequence(queue);
if (-1 == data)
{
printf("Dequence failed (queue empty)\n");
}
// 8.释放内存(可选,避免内存泄漏)
free(queue->Addr);
free(queue);
queue = NULL;
return 0;
}
测试结果
