数据结构 | 队列:从概念到实战

数据结构 | 队列:从概念到实战

个人主页-爱因斯晨

文章专栏-数据结构

继续加油!
在这里插入图片描述

文章目录

一、队列的基本概念

队列是一种先进先出(FIFO,First In First Out) 的线性数据结构,仅允许在一端进行插入操作(队尾),另一端进行删除操作(队头)。

生活中的队列场景:

  • 银行窗口排队办理业务
  • 打印机任务队列
  • 消息队列中的消息传递

二、队列的核心操作

  1. 初始化(InitQueue:创建一个空队列
  2. 入队(EnQueue:在队尾插入元素
  3. 出队(DeQueue:从队头删除元素
  4. 获取队头元素(GetFront:返回队头元素值
  5. 判空(IsEmpty:判断队列是否为空
  6. 销毁(DestroyQueue:释放队列占用的内存

三、C 语言实现队列

3.1 顺序队列(数组实现)

顺序队列使用数组存储元素,通过队头指针(front)和队尾指针(rear)标记队列边界。

#include<stdio.h>#include<stdlib.h>#defineMAX_SIZE100// 队列最大容量// 顺序队列结构体typedefstruct{int data[MAX_SIZE];int front;// 队头指针(指向队头元素)int rear;// 队尾指针(指向队尾元素的下一个位置)} SeqQueue;// 初始化队列voidInitQueue(SeqQueue *q){ q->front =0; q->rear =0;}// 判空intIsEmpty(SeqQueue *q){return q->front == q->rear;}// 判满intIsFull(SeqQueue *q){return(q->rear +1)% MAX_SIZE == q->front;// 预留一个空间区分空满}// 入队intEnQueue(SeqQueue *q,int value){if(IsFull(q)){printf("队列已满,无法入队\n");return0;// 入队失败} q->data[q->rear]= value; q->rear =(q->rear +1)% MAX_SIZE;// 循环移动队尾指针return1;// 入队成功}// 出队intDeQueue(SeqQueue *q,int*value){if(IsEmpty(q)){printf("队列为空,无法出队\n");return0;// 出队失败}*value = q->data[q->front]; q->front =(q->front +1)% MAX_SIZE;// 循环移动队头指针return1;// 出队成功}// 获取队头元素intGetFront(SeqQueue *q,int*value){if(IsEmpty(q)){printf("队列为空,无队头元素\n");return0;}*value = q->data[q->front];return1;}// 测试顺序队列intmain(){ SeqQueue q;InitQueue(&q);// 入队操作EnQueue(&q,10);EnQueue(&q,20);EnQueue(&q,30);// 获取队头元素int frontVal;GetFront(&q,&frontVal);printf("队头元素:%d\n", frontVal);// 输出:10// 出队操作int deVal;DeQueue(&q,&deVal);printf("出队元素:%d\n", deVal);// 输出:10// 再次获取队头GetFront(&q,&frontVal);printf("新队头元素:%d\n", frontVal);// 输出:20return0;}

顺序队列特点

  • 优点:实现简单,访问速度快
  • 缺点:容量固定,存在 “假溢出” 问题(需用循环队列优化)

3.2 链式队列(链表实现)

链式队列使用链表存储元素,队头指针指向头节点,队尾指针指向尾节点。

#include<stdio.h>#include<stdlib.h>// 节点结构体typedefstructNode{int data;structNode*next;} Node;// 链式队列结构体typedefstruct{ Node *front;// 队头指针(指向头节点) Node *rear;// 队尾指针(指向尾节点)} LinkQueue;// 初始化队列voidInitQueue(LinkQueue *q){// 创建头节点(不存储数据) Node *head =(Node*)malloc(sizeof(Node)); head->next =NULL; q->front = head; q->rear = head;}// 判空intIsEmpty(LinkQueue *q){return q->front == q->rear;}// 入队voidEnQueue(LinkQueue *q,int value){// 创建新节点 Node *newNode =(Node*)malloc(sizeof(Node)); newNode->data = value; newNode->next =NULL;// 插入到队尾 q->rear->next = newNode; q->rear = newNode;// 更新队尾指针}// 出队intDeQueue(LinkQueue *q,int*value){if(IsEmpty(q)){printf("队列为空,无法出队\n");return0;} Node *temp = q->front->next;// 待删除节点*value = temp->data; q->front->next = temp->next;// 如果删除的是最后一个节点,需更新队尾指针if(q->rear == temp){ q->rear = q->front;}free(temp);// 释放节点内存return1;}// 获取队头元素intGetFront(LinkQueue *q,int*value){if(IsEmpty(q)){printf("队列为空,无队头元素\n");return0;}*value = q->front->next->data;return1;}// 销毁队列voidDestroyQueue(LinkQueue *q){// 释放所有节点while(q->front !=NULL){ q->rear = q->front->next;free(q->front); q->front = q->rear;}}// 测试链式队列intmain(){ LinkQueue q;InitQueue(&q);// 入队EnQueue(&q,100);EnQueue(&q,200);EnQueue(&q,300);// 获取队头int frontVal;GetFront(&q,&frontVal);printf("队头元素:%d\n", frontVal);// 输出:100// 出队int deVal;DeQueue(&q,&deVal);printf("出队元素:%d\n", deVal);// 输出:100// 销毁队列DestroyQueue(&q);return0;}

链式队列特点

  • 优点:容量动态扩展,不存在溢出问题
  • 缺点:需要额外空间存储指针,操作稍复杂

四、队列的应用场景

  1. 广度优先搜索(BFS):在二叉树层次遍历、图的遍历中常用
  2. 缓冲处理:如键盘输入缓冲、网络数据接收缓冲
  3. 任务调度:操作系统中的进程调度、线程池任务调度
  4. 消息传递:分布式系统中的消息队列(如 RabbitMQ)

五、两种实现的对比选择

场景推荐实现理由
已知数据量且固定顺序队列效率更高,无需额外指针开销
数据量动态变化链式队列避免空间浪费和溢出问题
频繁插入删除链式队列操作更高效(O (1) 时间复杂度)
对内存使用敏感顺序队列内存连续分配,缓存利用率高

Read more

【Prometheus】如何通过prometheus监控springboot程序运行状态,并实时告警通知

【Prometheus】如何通过prometheus监控springboot程序运行状态,并实时告警通知

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,ZEEKLOG全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi,flask等框架,云原生k8s,Prometheus监控,linux,shell脚本等实操经验,网站搭建,数据库等分享。 所属的专栏:Prometheus监控系统零基础到进阶 景天的主页:景天科技苑 文章目录 * prometheus监控spring boot程序 * 1、下载jmx-exporter * 1. 访问github下载 * 2. 准备config.yml配置文件 * 2、运行SpringBoot应用 * 1. 安装java基础环境 * 2. 下载java应用然后进行编译

By Ne0inhk
MySQL的数据类型

MySQL的数据类型

MySQL的数据类型 * 1.数据类型分类 * 2.数值类型 * 2.1.tinyint类型 * 2.2.bit类型 * 2.3.float类型 * 2.4.decimal类型 * 3.字符串类型 * 3.1.char类型 * 3.2.varchar类型 * 3.3.char和varchar比较 * 4.日期和时间类型 * 5.enum和set类型 🌟🌟hello,各位读者大大们你们好呀🌟🌟 🚀🚀系列专栏:【MySQL的学习】 📝📝本篇内容:数据类型分类;数值类型;tinyint类型;bit类型;float类型;decimal类型;字符串类型;char类型;varchar类型;char和varchar比较;日期和时间类型;enum和set类型 ⬆⬆⬆⬆上一篇:

By Ne0inhk
Apple Silicon核心arm64 架构MAC部署openclaw

Apple Silicon核心arm64 架构MAC部署openclaw

背景:  周末尝试部署了一下最近大火的小龙虾 。发现arm64的装起来跟普通的似乎不太一样 。特地写个文档给大家解决一下问题  我的mac是 Apple Silicon(M1/M2/M3/M4,arm64 架构)。 环境准备: 注意命令必须运行在原生的终端里 首先检查一下你的node版本 node -v 确认node架构 node -e "console.log(process.platform, process.arch)" * 如果输出 darwin x64 → 就是 Rosetta/x64 问题。 * 应该输出 darwin arm64 才对。 如果node版本比较低或者架构不对。比如14.几 建议升级到最新版22  nvm install 22 --reinstall-packages-from=current # 这会自动选

By Ne0inhk
详解Spring AOP篇三

详解Spring AOP篇三

目录 代理模式 定义 代理模式的主要角色 静态代理 动态代理 JDK动态代理 接口介绍 CGLIB动态代理 Spring AOP源码解析 验证 没实现接口 实现了接口  小结 Spring AOP 是基于动态代理来实现AOP的. 代理模式 代理模式, 也叫委托模式. 定义 为其他对象提供⼀种代理以控制对这个对象的访问. 它的作⽤就是通过提供⼀个代理类, 让我们在调⽤⽬标⽅法的时候, 不再是直接对⽬标⽅法进⾏调⽤, ⽽是通过代理类间接调⽤. 在某些情况下, ⼀个对象不适合或者不能直接引⽤另⼀个对象, ⽽代理对象可以在客⼾端和⽬标对象之间起到中介的作⽤. 使⽤代理前: 使用代理后: 代理模式的主要角色 1. Subject: 业务接⼝类.

By Ne0inhk