C++抽象编程——STL(3)——离散事件模拟与排队问题

PS:我记得在数据结构的书上也有讲这个事件,但是说实话,讲的太抽象了,不如这本教材讲的透彻,接地气,而且讲了很多很多有意义的思考方式和处理方式,用的是熟悉的C++代码。我当时看的是全英文的,所以我只能是半翻译半理解的,加油

队列(queue)在模拟等待行为的程序中很常见。例如,如果你想要在超市中确定需要多少收款人,可能需要编写一个可以模拟商店客户行为的程序。 这样的程序肯定会涉及队列,因为结帐线以先入先出的方式运行。 已完成购买的客户到达结帐线,等待轮到支付。 每个客户最终都会到达线路的前面,在这个时间,收银员总计购买并收取钱。 因为这种类型的模拟代表了一类重要的应用程序,所以值得花点时间了解这种模拟是如何工作的。

Simulations and models (模拟与模式)

除了编程世界之外,还有各种各样的现实世界的事件和过程,尽管它们的重要性是无可否认的,但是它们完全不能完全理解。 例如,知道各种污染物质如何影响臭氧层将是非常有用的,臭氧层的变化如何影响全球气候。 同样,如果经济学家和政治领导人对国家经济如何运作有更全面的了解,就可以评估资本增值税的削减是否会刺激投资,还是会加剧现有的财富和收入差距?
当遇到这样的大规模问题时,通常需要提出一个理想化的模式(model),一个现实世界过程的简化表示。 大多数问题太复杂了,因为有太多的细节使人不能完全理解。 构建模型的原因在于,尽管存在特定问题的复杂性,但通常可以做出一些允许你简化复杂过程而不影响其基本特征的假设。 如果你可以为过程提出合理的模型,则可以将模型动态转换为捕获该模型行为的程序。 这样的程序称为模拟(simulation)。
创建模拟通常是两步过程。 第一步是为你尝试模拟的真实世界行为设计一个概念模型。 第二步包括编写实现概念模型的程序。 因为错误可能发生在这个过程的两个步骤中,维持对模拟的一些怀疑及其对现实世界的适用性可能是明智之举。 在一个有机会相信计算机提供的“答案”的社会中,认识到这些模拟永远不会比它们所依赖的模型更为重要。(it is critical to recognize that the simulations can never be better than the models on which they are based.

The waiting-line model(排队模型)

假设你想设计一个模拟超市排队行为的模拟。 通过模拟排队,您可以确定等待线路的一些有用的属性,这可能有助于公司做出如何需要多少收款人的决定,为线路本身保留多少空间等等。

编写仿真过程的第一步是为排队开发模型,详细说明简化的假设。 例如,为了使模拟的初始实现尽可能简单,您可以从假设有一个收银员为单个队列中的客户提供服务。 您可能会假设客户以随机概率到达,并在行尾输入队列。 每当出纳员空闲的时候,有人正在排队等候时,收银员开始为该客户服务。 在适当的服务期限之后,您也必须以某种方式进行建模 - 收银员与当前客户完成交易,并可为排队中的下一个客户提供服务。

Discrete time (离散时间)

模型中经常需要的另一个假设是对精度水平的一些限制。 例如,考虑客户由收银员服务的时间。 一个客户可能花两分钟时间;,另一个可能花费六分钟。 然而,重要的是考虑以分钟为单位的测量时间是否允许模拟足够精确。 如果你有一个足够精确的秒表,你可能会发现一个客户实际花了3.14159265分钟。 您需要解决的问题是您需要做多么准确,或者说你需要怎么样的准确程度。

对于大多数模型,特别是对于那些用于模拟的模型,引入模型中的所有事件以离散时间单位发生的简化假设是有用的。 使用离散的时间假设你可以找到一个时间单位,你可以视为不可分割的。 通常,仿真中使用的时间单位必须足够小,以致在单个时间单位内发生的多于一个事件的概率可以忽略不计。 在结帐线模拟中,例如分钟可能不够准确; 两个客户可以在同一分钟内轻松抵达。 另一方面,您可能无法使用秒数作为时间单位,因为可能忽略了两位客户完全相同的秒数。

虽然结这个示例假设模拟时间以秒为单位测量,但一般来说,没有理由必须以常规单位测量时间。 编写模拟时,可以以适合模型结构的任何方式定义时间单位。 例如,您可以将时间单位定义为五秒钟,然后以五秒间隔的间隔运行模拟。

Events in simulated time(模拟时间中的事件)

使用离散时间单位的真正优势并不在于它可以实现使用类型int的变量,而不被强制使用类型double。离散时间的最重要的属性是它允许你将模拟结构作为循环,其中每个时间单位表示单个周期(比如这里是5秒一次)。 当您以这种方式解决问题时,仿真程序具有以下形式:

for (int time = 0; time < SIMULATION_TIME; time++) {
    Execute one cycle of the simulation./*执行一轮模拟*/
    }

循环体内,在一个单位的模拟时间,程序执行必要的模拟操作。

此时,让我们再想一下,在结帐线模拟的每个时间单位中可能发生什么事件。一种可能性是新的客户可能会到达。另外还有一点是,收银员可能会与当前客户完成结账,并且为下一个人服务。这些事件带来了一些有趣的问题。比如要完成该模型,你需要说明客户到达时间的频率以及他们在收银机上花多少时间。你可以(也可能应该)通过在商店中观看真实的结帐线来收集近似数据。然而,即使你收集这些信息,你需要将其简化为以下形式:(
1. 捕获足够的真实世界行为才能有用(就是说要做大量的调查)
2. 在模型方面易于理解。例如,您的调查可能会显示客户平均每20秒到达一次。这个平均到达率对模型肯定是有用的。另一方面,对于每20秒内客户完全会来一次的模拟,您肯定不会有太多的信心。这样的实施将违反客户到达有一些随机变化的现实条件,比如它们有时会同时到达。

因此,到达过程通常通过指在任何离散时间单位里到达而不是到达之间的平均时间的概率来建模。 例如,如果您的研究表明客户每20秒到达一次,客户在任何特定秒钟到达的平均概率将为1/20或0.05。 如果你假设在每个时间单位到达以等概率随机发生,则到达过程就符合泊松分布(Poisson distribution.)我想学过概率论的同学肯定见过知道这个理论。我当时是大一学的,最后读这本书的时候也忘得差不多的,所以我就去查了一下,大致如下:
泊松分布
想知道详细的就点击泊松分布

你也可以选择简化对服务特定客户需要多长时间的假设。 例如,如果您假设每个客户所需的服务时间在一定范围内均匀分布,则该程序更容易编写。因为这样我们就可以写一个randomInteger函数来选择服务时间。

Implementing the simulation(编写模拟程序)

即使它比本章中的其他程序更长,但是仿真程序的代码是很容易写入,我们记住模拟的核心是一个循环,运行时间为参数SIMULATION_TIME指示的秒数。 在每一秒钟,仿真执行以下操作:

  • 确定新客户是否到达,如果是,请将该这个人添加到该客户队列。(Determine whether a new customer has arrived and, if so, add that person to the queue.)
  • 如果收银员很忙,此时收银员不得不多花了另外一秒钟给当前客户。但是最终,都会在所需的服务时间内完成,这将使得出纳员得以空闲。(If the cashier is busy, note that the cashier has spent another second with the current customer. Eventually, the required service time will be complete,which will free the cashier.)
  • 如果收银员是空闲的,就会为在等待线上为下一位顾客服务(If the cashier is free, serve the next customer in the waiting line.)

分析了那么多,我的下一篇博文就会写上这篇文章的代码跟分析,跟大家一起学习。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值