C语言 循环队列
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
在实际使用队列时,为了使队列空间能重复使用,往往对队列的使用方法稍加改进:无论插入或删除,一旦rear指针增1或front指针增1 时超出了所分配的队列空间,就让它指向这片连续空间的起始位置。指针从MaxSize-1增1变到0,可用取余运算rear%MaxSize和front%MaxSize来实现。这实际上是把队列空间想象成一个环形空间,环形空间中的存储单元循环使用,用这种方法管理的队列也就称为循环队列。
使用循环队列虽然可以解决顺序队列中浪费内存的问题,但这里任然存在一个问题,就是对于循环队列而言,队空和队满的条件都是rear==front,导致两种情况无法区分。
解决问题的办法:
方法1:增加一个参数,用来记录数组中当前元素的个数;
方法2:少用一个存储空间,也就是数组的最后一个存数空间不用,当(rear+1)%maxsiz=front时,队列满;
方法3:空队列用-1表示。
#include <stdio.h>
#define QUEUE_SIZE 3
int circularQueue[QUEUE_SIZE];
int front = -1; // 队列前部
int rear = -1; // 队列后部
// 检查队列是否为空
int isEmpty() {
return front == -1 && rear == -1;
}
// 检查队列是否已满
int isFull() {
return (rear + 1) % QUEUE_SIZE == front;
}
// 插入元素到队列
void enqueue(int value) {
if (isFull()) {
printf("enqueue: Queue is full. Cannot enqueue.\n");
} else {
if (isEmpty()) {
front = rear = 0;
} else {
rear = (rear + 1) % QUEUE_SIZE;
}
printf("enqueue: front %d, rear %d",front,rear);
circularQueue[rear] = value;
printf(" => %d\n", value);
}
}
// 从队列中删除元素
void dequeue() {
if (isEmpty()) {
printf("Queue is empty. Cannot dequeue.\n");
} else {
printf("Dequeued: => %d\n", circularQueue[front]);
if (front == rear) {
// 队首等于队尾,说明只有1个元素了,删除后等于是空队列,全部初始化为-1
front = rear = -1;
} else {
// 否则只要队首右移1位,打印从队首开始,相当于删除原队首
// front和rear都是下标,所以不能超过数组大小,通过取余%来重置。
// 比如数组大小为5,那么下标最大为4,那么(4+1)%5,只能取得0到4的下标,超过4就重置为0.
front = (front + 1) % QUEUE_SIZE;
}
}
}
// 打印队列元素
void display() {
if (isEmpty()) {
printf("Queue is empty.\n");
} else {
int i = front;
printf("display: front %d, rear %d\n",front,rear);
while (1) {
printf("%d ", circularQueue[i]);
if (i == rear) {
break;
}
i = (i + 1) % QUEUE_SIZE;
}
printf("\n");
}
}
int main() {
enqueue(1);
enqueue(2);
enqueue(3);
display();
dequeue();
display();
dequeue();
display();
enqueue(4);
display();
enqueue(5);
display();
for(int i=0;i<QUEUE_SIZE;++i){
printf("circularQueue[%d] = >%d\n",i,circularQueue[i]);
}
return 0;
}
以下是打印的内容
enqueue: front 0, rear 0 => 1
enqueue: front 0, rear 1 => 2
enqueue: front 0, rear 2 => 3
//队列为空时,初始化 front 和 rear 都为0
//为空时直接在rear=0处插入,否则 rear+1后再插入。
display: front 0, rear 2
1 2 3
//打印从front开始,当front=rear时结束,所以每次最后需要front+1,。
Dequeued: => 1
display: front 1, rear 2
//如果删掉 队首,front+1,所以只打印了最后2个
2 3
Dequeued: => 2
display: front 2, rear 2
3
//继续删除 队首,现在只剩最后1个了
enqueue: front 2, rear 0 => 4
display: front 2, rear 0
3 4
//上次插入时rear=2,已经是数组的最大指针了,插入后rear+1,rear重置为0,所以这里的4实际插入在数组下标0中
//打印从下标2开始,同样2是数组的最大指针,打印后front+1,front重置为0,所以能顺次打印出 下标2和下标0
//打印后判断front和rear是否相等,这里都等于0,所以打印结束。如果不相等,front+1,然后继续打印。
enqueue: front 2, rear 1 => 5
display: front 2, rear 1
3 4 5
circularQueue[0] = >4
circularQueue[1] = >5
circularQueue[2] = >3
//打印下标是2,0,1,所以输出3,4,5 数组实际排序是4,5,3
队列已满的测试
int main() {
enqueue(1);
enqueue(2);
enqueue(3);
dequeue();
display();
enqueue(4);
enqueue(5);
return 0;
}
打印内容
enqueue: front 0, rear 0 => 1
enqueue: front 0, rear 1 => 2
enqueue: front 0, rear 2 => 3
Dequeued: => 1
display: front 1, rear 2
2 3
//删掉队首后,下标是1,2
enqueue: front 1, rear 0 => 4
//重新插入,现在又有3个元素了,下标是1,2,0
enqueue: Queue is full. Cannot enqueue.
//数组最大是3个元素,所以再次插入就失败了,rear+1等于front
//front=0时,3个元素的下标就分别是0,1,2
//front=1时,3个元素的下标就分别是1,2,0
//front=2时,3个元素的下标就分别是2,0,1
相关知识:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具