专栏持续更新中关注博主不迷路跟着专栏系统学C语言底层开发从语法入门到工程实战逐章拆解保姆级讲解刚入门的同学跟着学全程零压力上一节我们掌握了抽象数据类型ADT的设计方法学会了把数据结构和操作打包成模块对外只暴露干净利落的函数接口。今天我们要把这项技能用在一个非常有趣的地方——用队列来模拟现实生活中的排队场景。你可能觉得“队列”只是个简单的先进先出FIFO数据结构但它在真实世界中的应用无处不在银行柜台前的顾客、机场跑道上等待起飞的飞机、操作系统里排队等待CPU处理的任务、你刷短视频时后台的请求队列……掌握了队列模拟你就能用C语言回答这样的问题一个咨询摊位平均每小时能接待多少顾客每位顾客平均要等多久排队等待的顾客平均有多少人摊位需要设置多少个座位才够用这些问题不需要真的去街上蹲一天——用程序模拟几千个顾客几分钟就能得到有统计意义的答案。这就是数据结构 编程的威力。本节核心知识点梳理提前划重点方便后续对照学习问题建模如何把现实中的排队场景抽象为程序中的数据结构随机数生成用rand()模拟顾客到达间隔和服务时长的随机性队列 ADT 的复用直接使用之前学过的队列模块不必重复造轮子模拟循环的核心逻辑以“分钟”为单位推进仿真时钟处理到达、服务、离开事件数据统计与分析从模拟中提取平均等待时间、平均队列长度、每小时服务人数等指标。一、问题描述商业街上的咨询摊位1.1 场景设定假设 Sigmund Landers 在商业街设置了一个提供付费建议的摊位。规则如下顾客可以购买1分钟、2分钟或3分钟的建议咨询服务时长为确保商业街人流畅通每个摊位前排队等待的顾客最多为10人即队列最大长度为10顾客是随机出现的到达间隔不确定每位顾客的服务时长也是随机选择的1、2或3分钟如果顾客到达时队列已满10人该顾客直接离开损失一位顾客。我们要回答的核心问题Sigmund 平均每小时能接待多少名顾客每位顾客平均花在咨询上的时间是多少排队等待的顾客平均有多少人有多少顾客因为队列满而流失1.2 为什么队列是最合适的数据结构这个问题天然符合队列的“先进先出”特性先来的顾客先接受服务后来的顾客排在队尾服务完的顾客从队首离开。队列在这里就是顾客排队的数字化身。1.3 模拟策略以“分钟”为单位推进我们将模拟时间以分钟为最小单位进行推进。每一分钟里会发生以下事件步骤事件模拟操作1是否有新顾客到达用随机数决定如果到达且队列未满则入队2当前是否有顾客正在接受服务如果是剩余服务时间减1分钟3服务是否刚好完成如果是让该顾客出队统计其等待时间4如果服务完成且队列非空从队列中取出下一位顾客开始服务这就是离散事件模拟的核心循环。程序运行几千个这样的“分钟”后就能得出有统计意义的结论。二、随机数的艺术让模拟更真实2.1 顾客到达的随机性现实中顾客不是排着队准时出现的。假设平均每 3 分钟来一位顾客但实际间隔可能是1分钟、5分钟、甚至连续来两位。我们怎么模拟这种“随机感”C 语言的rand()函数生成一个 0 到RAND_MAX之间的伪随机整数。通过与运算可以得到指定范围内的随机数#includestdlib.h#includetime.h// 在 main 开头调用一次用当前时间做种子确保每次运行结果不同srand((unsignedint)time(NULL));// 生成 1 到 3 之间的随机整数代表 1分钟、2分钟 或 3分钟intservice_timerand()%31;2.2 到达概率的设定假设平均每 3 分钟来一位顾客则每一分钟有 1/3 的概率来一位新顾客。我们可以这样模拟// 每一分钟执行一次if(rand()%30){// 概率约为 1/3// 来了一位新顾客if(queue_sizeMAX_QUEUE_SIZE){queue_enqueue(q,service_time);}else{customers_lost;// 队列满顾客流失}}2.3 服务时长的随机性每位顾客购买的建议时长是随机的1、2或3分钟intservice_timerand()%31;// 1, 2, 或 3三、模拟程序的完整实现3.1 需要统计的数据在开始编写模拟循环前先明确我们要收集哪些数据统计指标变量名含义接待顾客总数total_served成功接受服务并离开的顾客数量流失顾客总数total_lost因队列满而直接离开的顾客数量总等待时间total_wait_time所有顾客在队列中等待的分钟数之和总服务时间total_service_time所有顾客接受咨询的分钟数之和模拟总时长SIMULATION_MINUTES模拟多少分钟如 480 分钟 8小时通过这些原始数据可以计算出平均每小时接待人数 total_served / (SIMULATION_MINUTES / 60)平均等待时间 total_wait_time / total_served平均队列长度 total_wait_time / SIMULATION_MINUTES这段时间内累积的等待分钟数 ÷ 总分钟数近似等于任一时刻的平均排队人数流失率 total_lost / (total_served total_lost)3.2 完整代码#includestdio.h#includestdlib.h#includetime.h#defineMAX_QUEUE_SIZE10#defineARRIVAL_PROB3// 平均每3分钟来一位顾客概率 1/3#defineSIMULATION_MINUTES480// 模拟8小时480分钟// ---------- 队列 ADT 的简单实现内嵌版本便于教学 ----------structCustomer{intservice_time;// 该顾客需要的服务时长1~3分钟intwait_time;// 该顾客在队列中等待的分钟数入队时记录当前时间};structQueue{structCustomeritems[MAX_QUEUE_SIZE];intfront;intrear;intsize;};voidqueue_init(structQueue*q){q-front0;q-rear0;q-size0;}intqueue_is_full(structQueue*q){returnq-sizeMAX_QUEUE_SIZE;}intqueue_is_empty(structQueue*q){returnq-size0;}intqueue_enqueue(structQueue*q,structCustomerc){if(queue_is_full(q))return-1;q-items[q-rear]c;q-rear(q-rear1)%MAX_QUEUE_SIZE;q-size;return0;}structCustomerqueue_dequeue(structQueue*q){structCustomercq-items[q-front];q-front(q-front1)%MAX_QUEUE_SIZE;q-size--;returnc;}// ---------- 模拟主程序 ----------intmain(void){structQueueq;queue_init(q);srand((unsignedint)time(NULL));// 统计变量inttotal_served0;// 成功服务的顾客总数inttotal_lost0;// 因队列满而流失的顾客总数inttotal_wait_time0;// 所有顾客的总等待分钟数inttotal_service_time0;// 所有顾客的总服务分钟数intcurrent_service_remaining0;// 当前正在服务的顾客还剩余多少分钟0 表示空闲intcurrent_minute;// 模拟时钟的当前分钟数// 模拟主循环每分钟迭代一次for(current_minute1;current_minuteSIMULATION_MINUTES;current_minute){// 事件1是否有新顾客到达if(rand()%ARRIVAL_PROB0){// 概率 1/ARRIVAL_PROBif(!queue_is_full(q)){structCustomerc;c.service_timerand()%31;// 随机 1, 2, 3 分钟c.wait_timecurrent_minute;// 记录到达时刻后续计算等待时间queue_enqueue(q,c);}else{total_lost;// 队列满了顾客直接离开}}// 事件2当前是否有顾客正在接受服务if(current_service_remaining0){current_service_remaining--;// 服务时间减少 1 分钟// 事件3服务是否刚好完成if(current_service_remaining0){total_served;}}// 事件4如果当前空闲且队列非空从队列中取下一位顾客开始服务if(current_service_remaining0!queue_is_empty(q)){structCustomercqueue_dequeue(q);current_service_remainingc.service_time;total_wait_time(current_minute-c.wait_time);// 累计该顾客的等待分钟数total_service_timec.service_time;}}// 模拟结束输出统计结果printf( 模拟结果 \n);printf(模拟总时长%d 分钟约 %.1f 小时\n,SIMULATION_MINUTES,SIMULATION_MINUTES/60.0);printf(接待顾客总数%d 人\n,total_served);printf(流失顾客总数%d 人队列满\n,total_lost);printf(平均每小时接待%.1f 人\n,(double)total_served/(SIMULATION_MINUTES/60.0));if(total_served0){printf(每位顾客平均等待时间%.1f 分钟\n,(double)total_wait_time/total_served);printf(每位顾客平均服务时间%.1f 分钟\n,(double)total_service_time/total_served);}printf(平均队列长度%.2f 人\n,(double)total_wait_time/SIMULATION_MINUTES);printf(流失率%.1f%%\n,(double)total_lost/(total_servedtotal_lost)*100.0);return0;}3.3 运行结果示例 模拟结果 模拟总时长480 分钟约 8.0 小时 接待顾客总数142 人 流失顾客总数0 人队列满 平均每小时接待17.8 人 每位顾客平均等待时间0.7 分钟 每位顾客平均服务时间2.0 分钟 平均队列长度0.22 人 流失率0.0%新手重点因为每次运行用了srand(time(NULL))结果会稍有不同但大致趋势一致。这正是模拟的意义——通过反复运行得出一个统计范围而不是精确的单一数值。3.4 代码逐段拆解① 数据结构定义structCustomer{intservice_time;// 服务时长intwait_time;// 到达时刻用于计算等待时间};wait_time记录的是顾客入队时的分钟数当前模拟时钟的读数。当这位顾客最终被服务时用current_minute - c.wait_time就得到了他在队列中等待的总分钟数。② 模拟主循环的四步事件for(current_minute1;current_minuteSIMULATION_MINUTES;current_minute){// 事件1检查新到达// 事件2推进当前服务// 事件3检查服务完成// 事件4取下一位顾客}这个循环结构是离散事件模拟的通用模板换个场景同样适用。③ 统计变量的更新时机变量何时更新total_served服务完成时total_lost到达但队列满时total_wait_time顾客从队列中取出开始服务时total_service_time顾客从队列中取出时④ 平均队列长度的计算平均队列长度 总等待分钟数 / 模拟总分钟数这背后的原理是利特尔法则在一个稳定系统中平均排队人数 顾客到达率 × 平均等待时间。我们的计算方式等价于这个公式统计意义上合理。3.5 你可以调整的参数参数当前值如果调整为……会有什么变化MAX_QUEUE_SIZE105流失率飙升排队人数减少ARRIVAL_PROB3每3分钟来一位2每2分钟来一位顾客更多队列更长等待更久SIMULATION_MINUTES4808小时288048小时样本更大统计结果更稳定服务时长范围1~3分钟1~5分钟每位顾客占用更长时间队列积压更严重动手试一试改几个参数重新运行观察结果如何变化。这就是模拟的魅力——不需要真的去街上开个摊位就能提前预见各种情况。四、本章总结新手必看快速掌握核心核心知识点一句话总结问题建模把现实排队场景映射为队列数据结构1分钟为模拟时钟的最小单位随机数模拟rand() % N控制概率srand(time(NULL))保证每次运行结果不同四步事件循环到达检查 → 服务推进 → 完成处理 → 取下一位这是离散事件模拟的通用模板数据统计在关键事件点累计原始数据模拟结束后统一计算平均指标利特尔法则平均队列长度 总等待时间 / 总模拟时间参数可调队列容量、到达率、服务时长范围等参数都可以自由调整观察不同场景✅入门行动清单把上面的完整代码复制到 VS 中编译运行观察输出结果修改MAX_QUEUE_SIZE为 5重新运行对比流失率的变化修改ARRIVAL_PROB为 2顾客来得更频繁重新运行观察等待时间的变化尝试将模拟时长设为60 * 24模拟一整天看看结果是否更稳定思考一下你身边还有哪些场景可以用队列模拟食堂打饭地铁安检试试动手改编代码。队列模拟的魔法已经在你手里了。它不仅仅是一个数据结构练习更是把编程能力应用于解决现实问题的思维方式——从观察世界到建模抽象再到代码实现和数据分析这条链路是高级程序员的必备素养。关注博主专栏持续更新从基础到实战保姆级讲解 C 语言核心特性与工程技巧。队列之后我们将进入二叉树的世界——那是数据结构的又一个重要篇章。我们下一节见#C语言 #数据结构 #队列 #离散事件模拟 #随机数 #保姆级教程 #新手避坑 #嵌入式开发 #CSDN #C语言实战欢迎关注公众号获取更多技术干货 C语言宝藏资源包免费送14 本 C 经典书 编译工具全家桶 高效编程技巧搭配 C 语言精选书籍、20 算法源码 项目规范还有 C51 单片机 400 例实战从零基础到嵌入式开发全覆盖学生党、职场人直接抄作业 关注文章末尾的博客同名公众号回复【C 语言】一键解锁全部资源手慢也有​