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

相关知识:

数据结构:循环队列(C语言实现)

 

posted @   C羽言  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示