泡面编程 /第1章
如何泡一碗方便面
本节我们将从熟悉的泡面开始,了解算法的概念。
说起“程序”,我们对其并不陌生,因为它融入了我们生活的方方面面:手机的时钟程序在早上将我们叫醒,空调中的温控程序负责将家中调到合适的温度,汽车的导航程序指引我们如何到达目的地,红绿灯的运行程序有节奏地控制着车流……
程序确实是十分有趣的,不过它似乎有些神秘,好像是只有程序员或者黑客才能掌握的内容。
不过你现在没时间顾得上这些,因为眼前有一件更为急迫和重要的事情,直接关系到你朋友接下来会不会饿肚子。
一位平时并不怎么做家务的朋友刚才突然给你发消息:“江湖救急!现在就我一个人在家,我想泡一碗方便面吃,可我不会,快教我一下吧!”
于是,你赶紧给他写了一个详细的操作步骤:
- 第①步:将方便面从袋子中取出,放到干净的碗中。
- 第②步:将所有的调料包都取出,并依次拆开,倒入碗中。
- 第③步:向碗中注入适量开水。
- 第④步:用碟子盖住碗。根据喜欢吃的面的软硬程度,等待3到5分钟。
- 第⑤步:打开盖住碗的碟子,就可以吃面了。
以上步骤,或许泡出的方便面不是最美味的,例如没有讲怎么才能在里面顺便卧一个荷包蛋。但是,肯定是够用的,你知道按照这个步骤,你朋友一定能吃到一碗图 1一样的热腾腾的泡面。

于是,你赶紧将上述操作步骤发给了朋友。
但是你忘了,他可是一个很较真的人。很快,他给你回了信息:“我再问一下,你说的适量开水,可到底多少是适量啊?能说的再准确一点么?”,就像图 2展示的一样。

他的较真你是知道的,他问出这样的问题也不足为怪。毕竟,你刚才的表述中,确实存在一些歧义。
考虑到回答完他这个问题之后,他可能还会再问出“我再问下,我喜欢吃硬一点的面,到底是等待3分钟还是5分钟啊?”之类的问题,你于是决定直接再发一版给他。这一次,你十分仔细,力求消除任何歧义。
- 第①步:将方便面从袋子中取出,放到干净的600ml容量的空碗中。
- 第②步:将所有的调料包都取出,并依次拆开,倒入上述碗中。
- 第③步:向碗中注入500ml温度为100℃的水,并立刻用直径大于碗的碟子盖住碗。
- 第④步:如果喜欢硬一点的面,则等3分钟;如果喜欢软硬适中的面,则等4分钟;如果喜欢软一点的面,则等5分钟。
- 第⑤步:时间一到就打开盖住碗的碟子,就可以吃面了。
写完之后,你有读了几遍,还是发现了一些小的歧义点。以你对朋友的了解,他说不定还会问出“所有的调料包我是全取出来后都拆开然后依次倒入碗中,还是一包包依次取出来拆开倒入碗中呢?”
于是你继续斟酌,又写了一版:
- 第①步:将方便面从袋子中取出,放到干净的600ml容量的空碗中。
- 第②步:取出调料包,拆开,将调料倒入上述碗中。
- 第③步:检查是否还有调料包。如果有,重复第②步;如果没有,进入下一步。
- 第④步:向碗中注入500ml温度为100℃的水,并立刻用直径大于碗的碟子盖住碗。
- 第⑤步:如果喜欢硬一点的面,则等3分钟;如果喜欢软硬适中的面,则等4分钟;如果喜欢软一点的面,则等5分钟。
- 第⑥步:时间一到就打开盖住碗的碟子,就可以吃面了。
这样认真地修改是十分有必要的,毕竟你面对的是一位较真的好朋友,而这又是关系到他能否吃上饭的头等大事。
再三校验后,你觉着应该没有什么歧义了,于是将新的泡面步骤发给了他。
几分钟后,他回复:“收到!我这就去照做!”
这时你长舒一口气,不禁感叹道:原来我们平时讲话中,存在这么多歧义啊!只不过大家都忽略了罢了。要不是因为有这位较真的朋友,还真不容易发现这点。
现在,恭喜你的朋友,他在你的帮助下终于可以吃上热腾腾的泡面了。
也更要恭喜你,你在帮助朋友的过程中,梳理出了一个完全没有歧义的泡方便面的步骤。这可并不是一件容易的事情,因为我们平时的对话中,很多地方都有歧义,将它们一一找出来并改掉,并不简单。
事实上,你发给朋友的泡面步骤可以称之为“泡面算法”。或许“算法”这一词对你而言有些陌生,但它并不复杂。
算法就是解决特定问题的一系列明确的步骤或规则。
就在刚才,为了解决“如何泡一碗方便面”这一特定问题,你已经梳理出了泡面所需要的明确的操作步骤,以及对碗的容量、水的温度等的明确规则。所以,发给朋友的这份泡面步骤完全符合算法的定义,绝对可以称之为“泡面算法”。
既然聊到了算法,并且我们还自己写出了“泡面算法”,那有必要继续展开一下,了解下算法的主要特点,就是下面五个:
- 有穷性:算法必须在有限的步骤内结束,也就是说必须存在一个明确的终点,不能无限循环下去。我们的泡面算法中,在第③步拆调料包的过程中存在循环,但因为任何方便面的调料包都是有限的,总会被拆完,进而顺利进入第④步,不会在这里一直循环。最终整个泡面的步骤只要执行完第⑥步就结束了,所以整个泡面步骤满足有穷性。
- 可行性:算法中的每一步都必须是可行的。显然,我们泡面算法中的每一步都可以做到。
- 输入:算法可以有零个、一个或者多个输入。输入就是要提供给算法处理的东西。在泡面算法中,需要的输入有:一袋方便面、一个600ml容量的空碗、500ml温度为100℃的水、一个直径大于碗的碟子。虽然我们没有提前明确地向朋友说明他要准备好这些东西,但相信他只要读一遍步骤就能知道。
- 输出:算法可以有一个或者多个输出。输出就是算法执行完后,给出的东西。显然,泡面算法的输出就是一碗泡好的方便面。
- 确定性:算法的每一步操作必须有明确的定义,没有歧义,在相同输入的情况下,总会得到相同输出。这也是我们不断改写泡面步骤的原因,只有这样,才能确保不同时间、不同的人看到后都有相同的理解,总会做出相同的操作,进而保证只要输入一样,一定会得到相同的输出。我们的泡面算法经过不断改进后,最终满足了这一点。
想一想
你或许已经发现,算法可以有零个、一个或者多个输入,可以有一个或者多个输出。仔细对比我们会发现,算法可以有零个输入,但是不能有零个输出,这是为什么呢?
有些算法确实不需要输入,例如一个算法的功能可以是给出一个随机数,那它就不需要输入。每次执行这个算法时,算法通过内部的机制给出一个随机数即可。
算法在执行过程中,可以给出一个内容、让电脑等待一些时间、在屏幕上显示一个字符等等,这些都算它的输出。而如果一个算法没有任何输出,那就没有存在的意义,当我们使用这个算法时,也没法感知这个算法是不是正常工作。所以算法通常是有输出的。
算法实际上是给出了解决问题的步骤,如果我们将每一步都按照编程语法写出来,就得到了程序。我们可以把算法比作是解答一到数学题的解题思路,而程序就是按照数学符号写出来的解题步骤。可见,算法就是程序的灵魂。
现在我们已经写出了泡面算法,这意味着,将来我们可以写出泡面程序。说到这里,你或许会疑惑:我们的泡面算法中的每一步都是给人看的,计算机难以实现取方便面、倒热水等操作,似乎很难转化为计算机程序。
不,可别丧气。后面我们这真的会将这一切都转化为计算机程序,让计算机帮我们泡面。
不过,这是后面几章的事情。在此之前,我们还有不少的知识要学。