某银行有一个客户办理业务站,在一天内随机地有客户到达,设每位客户的业务办理时间是某个范围内的值。设只有一个窗口,一位业务人员,要求程序模拟统计在
一天时间内,所有客户的平均等待时间。模拟数据按客户到达的先后顺序依次由键盘输入,对应每位客户有两个数据,到达时刻和需要办理业务的时间。

输入格式
第一行:一天内的客户总人数n
第二行:第一个客户的到达时刻和需要办理业务的时间
第三行:第二个客户的到达时刻和需要办理业务的时间
……
第n行:第n - 1个客户的到达时刻和需要办理业务的时间
第n + 1行:第n 个客户的到达时刻和需要办理业务的时间

输出格式
第一行:所有客户的平均等待时间(精确到小数点后2位)

输入样例
3
1 3
2 1
3 5

输出样例
1.33

基本思路:
1、定义一个结构体,表示的是一个人。其中这个结构体数组中的成员属性主要有两个,两个double类型的变量from,wait,表示这个人来到银行的时间以及办理业务所需要的时间。

typedef struct NODE{double from;double wait;
}Node;

2、定义一个循环队列,从而在初始化队列的时候,不至于分配较大的内存空间,从而造成内存空间的浪费。
3、输入数字n表示银行一共会有多少人来
4、输入from,wait两个数字,from表示新人T来到银行的时间,wait表示这个人需要办理业务所需要的时间。
5、如果队列为空,表示这个新输入的人前面没有人,所以不需要排队,这时候,我们直接将这个新人T压入到队列中;如果队列不为空,那么从队列中跳出一个人P,然后将这个P最后办理完业务的时间end和T刚刚来到银行的时间newFrom进行比较,如果end小于等于newFrom,那么新人T不需要等待,直接就可以进行办理业务,否则,需要等待,等待的时间为end - newFrom
6、重复4、5的操作,直到输入完了n个人的数据,这时候,我们就可以将所需要等待的平均时间输出了。
对应的代码:

#include<stdio.h>
#include<stdlib.h>
#define ERROR 0
#define OK 1
#define QUEUE_SIZE 100
typedef struct NODE{double from;//办事开始的时间double end;//办事结束的时间
}Node;
typedef struct QUEUE{Node *arr;//定义一个Node类型的指针变量,表示要排队的人int front;int rear;int size;//表示队列的大小
}Queue;
int initQueue(Queue &queue){//将队列初始化queue.arr = (Node *)malloc(sizeof(Node) * QUEUE_SIZE);if(queue.arr == NULL)return ERROR;queue.front = 0;queue.rear = 0;queue.size = QUEUE_SIZE;return OK;
}
//压队操作
int push(Queue &queue,double from,double end){//如果栈为满,那么就回到最开始的时候if((queue.rear + 1) % queue.size == queue.front){printf("队列为满!!!\n");return ERROR;//栈为满,那么返回ERROR,表示压队错误}queue.arr[queue.rear].from = from;queue.arr[queue.rear].end = end;queue.rear = (queue.rear + 1) % queue.size;return OK;
}
//出队操作
int pop(Queue &queue,double &from,double &end){//判断队列是否为空,如果为空,那么返回ERRORif(queue.rear == queue.front)return ERROR;/*printf("删除的人起始时间:%.0f,结束时间:%.0f,办事时间:%.0f\n",queue.arr[queue.front].from,queue.arr[queue.front].from + queue.arr[queue.front].end,queue.arr[queue.front].end);*/from = queue.arr[queue.front].from;end = queue.arr[queue.front].end;queue.front = (queue.front + 1) % queue.size;return OK;
}
//获取队列头节点的起始时间,结束时间
int getTop(Queue &queue,double &from,double &end){if(queue.rear == queue.front)return ERROR;/*printf("队列头起始时间:%.0f,结束时间:%.0f,办事时间:%.0f\n",queue.arr[queue.front].from,queue.arr[queue.front].from + queue.arr[queue.front].end,queue.arr[queue.front].end);*/from = queue.arr[queue.front].from;end = queue.arr[queue.front].end;return OK;
}
int isEmpty(Queue &queue){return queue.front == queue.rear;//判断队列是否为空
}
int main(){Queue queue;int n,i;double from,end,wait = 0,newFrom,newWait;double time = 0;//表示要等待的时间if(!initQueue(queue)){printf("创建队列失败!!!\n");exit(0);}scanf("%d",&n);//输入有n个人需要办事for(i = 1; i <= n; i++){scanf("%lf%lf",&newFrom,&newWait);//输入新人排队的时间以及办事的时间
/*
判断队列是否为空,如果队列不为空,那么不断从队列中跳出一个人P出来,将这个从队列中跳出来的人结束办理业务的时间end和新来银行办理业务的人T的时间newFrom进行比较,如果end大于newFrom,说明新来银行的人需要等待end - newFrom时间,否则不需要等待。重复这一步,直到队列为空,才将新来银行的人压入到队列中
*///这里也可以将while(!isEmpty(queue))来替换if判断,结果是一样的if(!isEmpty(queue)){pop(queue,from,wait);//获取新来银行的人T前面正在办事的人Pend = wait + from;//P结束办理业务的时间// printf("上一个人来的时间:%.0f,办理业务结束的时间:%.0f\n",from,end);if(end > newFrom){//如果P结束办理业务的时间大于T刚来银行的时间,那么就说明T需要等待end - newFrom时间time += end - newFrom;//   printf("第%d个人需要等待的时间为:%.0f\n",i,end - newFrom);/*(这一步非常重要,因为新来的人T需要等待时间,所以P结束办理业务的时间就是T开始办理业务的时间)*/newFrom = end;//更改后面排队的人开始办事的时间}}//   printf("第%d个人开始办理事务的时间%.0f,办事的时间%.0f,最终结束的时间是:%.0f\n",i,newFrom,newWait,newFrom + newWait);//可以用于检验是否正确,或者说哪一块出现了问题push(queue,newFrom,newWait);//队列为空的时候,将新来银行的人P压入到队列中}printf("%.2f",time / n);return 0;
}

测试用例:

用例二:

好的,看完了对应的代码,接下来我们来解析一下步骤5的代码

  for(i = 1; i <= n; i++){scanf("%lf%lf",&newFrom,&newWait);//输入新人排队的时间以及办事的时间
/*
判断队列是否为空,如果队列不为空,那么不断从队列中跳出一个人P出来,将这个从队列中跳出来的人结束办理业务的时间end和新来银行办理业务的人T的时间newFrom进行比较,如果end大于newFrom,说明新来银行的人需要等待end - newFrom时间,否则不需要等待。重复这一步,直到队列为空,才将新来银行的人压入到队列中
*/if(!isEmpty(queue)){pop(queue,from,wait);//获取新来银行的人T前面正在办事的人Pend = wait + from;//P结束办理业务的时间// printf("上一个人来的时间:%.0f,办理业务结束的时间:%.0f\n",from,end);if(end > newFrom){//如果P结束办理业务的时间大于T刚来银行的时间,那么就说明T需要等待end - newFrom时间time += end - newFrom;//   printf("第%d个人需要等待的时间为:%.0f\n",i,end - newFrom);/*(这一步非常重要,因为新来的人T需要等待时间,所以P结束办理业务的时间就是T开始办理业务的时间)*/newFrom = end;//更改后面排队的人开始办事的时间}}//   printf("第%d个人开始办理事务的时间%.0f,办事的时间%.0f,最终结束的时间是:%.0f\n",i,newFrom,newWait,newFrom + newWait);//可以用于检验是否正确,或者说哪一块出现了问题push(queue,newFrom,newWait);//队列为空的时候,将新来银行的人P压入到队列中}

好的,看完这个代码,有人就会问了,为什么在获取等待的时间那里,if判断还可以通过while循环来进行判断呢?
我们通过画图来进行解析:

通过分析,我们可以知道,队列中只有一个人,表示新来到银行的人的前一个在办理业务的人。所以,就不用通过通过while,只要通过if来判断新来到银行的人是否需要等待即可,虽然可以通过while也有同样的效果,但是这里并没有必要哈。

错误的代码(之前做的时候,处理步骤五的代码):

  for(i = 1; i <= n; i++){scanf("%lf%lf",&newFrom,&newWait);//输入新人排队的时间以及办事的时间if(!isEmpty(queue)){getTop(queue,from,wait);//获取新来银行的人T前面正在办事的人Pend = wait + from;//P结束办理业务的时间// printf("上一个人来的时间:%.0f,办理业务结束的时间:%.0f\n",from,end);if(end > newFrom){//如果P结束办理业务的时间大于T刚来银行的时间,那么就说明T需要等待end - newFrom时间time += end - newFrom;pop(queue,from,wait);//   printf("第%d个人需要等待的时间为:%.0f\n",i,end - newFrom);/*(这一步非常重要,因为新来的人T需要等待时间,所以P结束办理业务的时间就是T开始办理业务的时间)*/newFrom = end;//更改后面排队的人开始办事的时间}}//   printf("第%d个人开始办理事务的时间%.0f,办事的时间%.0f,最终结束的时间是:%.0f\n",i,newFrom,newWait,newFrom + newWait);//可以用于检验是否正确,或者说哪一块出现了问题push(queue,newFrom,newWait);//队列为空的时候,将新来银行的人P压入到队列中}

通过仔细观察,我们可以知道,错误的代码和正确代码的区别主要在if判断中,正确代码是不管队列的人结束办理业务的时间是否大于新来银行的人来到银行的时间,都要将从队列中跳出一个人,但是错误的代码确实首先获取队列中的一个人,然后那这个人的结束办理业务的时间和新到银行的人到银行的时间进行比较,然后如果队列中跳出的人的办理业务的时间大于新银行的人道银行的时间,那么就从队列中跳出这个人。
嗯,看似效果是一样的,但是我们将行注释的内容显示一下,在进行比较,我们就可以知道为什么不可以使用错误的代码了。过程就不再分析了,大家可以尝试着将对应的样例写出,看看每一次新人到银行是队列中是什么样的,就知道错误代码为什么不可以。

队列的应用--银行客户的平均排队问题相关推荐

  1. JS 数据结构之旅 :通过JS实现栈、队列、二叉树、二分搜索树、AVL树、Trie树、并查集树、堆

    JS 数据结构之旅 栈 概念 栈是一个线性结构,在计算机中是一个相当常见的数据结构. 栈的特点是只能在某一端添加或删除数据,遵循先进后出的原则 实现 每种数据结构都可以用很多种方式来实现,其实可以把栈 ...

  2. 高并发系统设计:消息队列的三大作用:削峰填谷、异步处理、模块解耦

    削去秒杀场景下的峰值写流量 而在秒杀场景下,高并发的写请求并不是持续的,也不是经常发生的,而只有在秒杀活动开始后的几秒或者十几秒时间内才会存在.为了应对这十几秒的瞬间写高峰,将秒杀请求暂存在消息队列中 ...

  3. 网络中常用的队列管理方法比较

    队列管理属于链路IP层的拥塞控制策略,主要是在路由器中采用排队算法和数据包丢弃策略.排队算法通过决定哪些包可以传输来分配带宽,而丢弃策略通过决定哪些包被丢弃来分配缓存. 1.先进先出(FIFO,Fir ...

  4. [RabbitMQ]RabbitMQ深入理解(一)进阶/管理/配置

    2019独角兽企业重金招聘Python工程师标准>>> 本文源于朱忠华的<RabbitMQ实战指南> RabbitMQ简介 消息队列中间件有两种传递模式:点对点 和 发布 ...

  5. Oracle日常巡检

    所有企业的业务数据库系统都是重中之重,如何来保证系统安全性与稳定性,需要DBA每日来通过相应的巡检指标进行相关记录,今天我们就来简单说一下 OS健康检测 将CPU.内存.磁盘I/O状况.网络状况等填到 ...

  6. 删除单链上数据域值最小的节点_深入浅出数据结构

    作为一名前端开发工程师,你可能有时会问:学习数据结构或者算法对于前端工程师有用么? 总的来说,这些基础学科在短期内收效确实甚微,但是我们首先不要将自己局限在前端工程师这点上,当我们把视野放到编程这个角 ...

  7. 日均请求量百亿级数据处理平台的容器云实践

    from: http://geek.csdn.net/news/detail/97887 声明:本文为CSDN原创投稿文章,未经许可,禁止任何形式的转载.  作者:袁晓沛,目前在七牛云的主要工作是基于 ...

  8. linux系统性能优化及瓶颈分析

    一.用vmstat分析系统I/O情况 [root@localhost ~]# vmstat -n 3       (每一个3秒刷新一次) procs-----------memory--------- ...

  9. Python-OpenCV 处理视频(三)(四)(五): 标记运动轨迹 运动检测 运动方向判断

    0x00. 光流 光流是进行视频中运动对象轨迹标记的一种很常用的方法,在OpenCV中实现光流也很容易. CalcOpticalFlowPyrLK 函数计算一个稀疏特征集的光流,使用金字塔中的迭代 L ...

最新文章

  1. Alpha fold: 人工智能在蛋白质结构预测上跑赢人类的启示
  2. 概率图模型PGM——D map, I map, perfect map
  3. ORACLE 回滚段详解
  4. python算法与数据结构-数据结构中常用树的介绍
  5. 使用Hibernate生成数据库和连接数据库
  6. Google Xpath Helper
  7. 测试或运维工作过程中最常用的几个linux命令?
  8. ECMAScript6 ES6语法
  9. Android SQLite服务--创建、增删改查
  10. Mac 10.12安装迅雷2.7.2
  11. 《how to write and publis a scientific paper》 Chapter 3
  12. 【快代理】开放代理使用教程
  13. coreos mysql_CoreOS 实战:在 UOS上体验CoreOS 操作全记录
  14. 一种解决常见的80/443端口被占用导致steamcommunity 302服务无法启动的方法
  15. 香港服务器到大陆各地的网络延迟大小
  16. 系统封装教程(Win10案例)
  17. 大数据可视化,助力行业大数据应用
  18. vc6创建dll文件的步骤_创建真正有用的产品支持页面的6步骤计划
  19. 《即兴演讲》读书笔记
  20. 使用Idea下载源码报Cannot Download Sources

热门文章

  1. 通过Framebuffer刷屏使得屏幕显示红色
  2. 网络综合测试仪 手持信号综合分析仪 10G误码测试仪 SHD TFN TT70-S1
  3. android Room数据库了解
  4. 怎样用计算机算相关系数,如何用FRM计算器计算均值、标准差、相关性以及回归方程...
  5. 这些矫健的背影、可亲的脸庞,你记住了吗
  6. 聊聊我这不正的「用户观」 ofo退款与最后一公里之死
  7. WPF实现圆形菜单动态展开折叠效果
  8. NO.87 提前还款or买火鸡?(捎带举例JAVA Double精度计算问题)
  9. 关于下载uproot
  10. 【小白专区】求模运算符(%)的使用