从数字比较看计算中的思维
2019-06-20陈凯
陈凯
在学习程序语言时,初学者常会遇见这样的任务:输入三个数字,将它们从小到大排好序。图1是用Python代码实现此任务的例子。
任务目标很明确,实现任务的程序代码量也不多,然而,分支嵌套分支,其中再嵌套分支的结构有可能把人弄晕,虽然其中涉及的逻辑推理不难,但落实到程序语言上,想要把逻辑关系理顺,也不是一时半会儿的事情。乍看上去,这种通过多层分支嵌套解决问题的方式很“计算机”,距离人脑直观判别数字大小的方法很远,人类在面对三个不同大小的数字时,难道不是直观看上一眼后,就能瞬间把顺序排列好吗?
但只要多想一点,就会发现,认为“多层嵌套分支”很“计算机”的想法,未必是事实,因为在某些特殊的场景中,人类的确是需要以这种逻辑推理的方式来判别三个对象值的大小的。举例说,某任务要求用一个电压比较器比较三个触点电压的大小,因为电压比较器每次只能比较两个触点,所以就要利用类似分支嵌套的方式,来获知三个触点的电压相对大小的情况。
若再仔细思考,就会注意到,在各种不同的场景任务中,人其实是使用各种不同的方法来给对象值的大小进行排序的,而其中应用的灵活程度,恐怕连使用者自己也不知道。但借助算法的模拟,却反而能揭示出思维运作中的奥秘,以下再试举几例。
● 三棵白菜重量的排序
没有计量工具时,怎么快速估量出三棵白菜的重量并排序呢?若重量差异明显,那么用手掂一掂就可以了。但是白菜有三棵,手只有两只,怎么办?这个问题并不难办,不妨先找出最轻(或最重)的那一棵白菜。掂一棵白菜,记住它大概的重量,再掂另一棵,若它更轻(或更重),则记住它,否則就把它放到一边去,然后再掂最后一棵。用这样的办法找出最轻(或最重)的白菜,然后把它放到第一位(或最后一位)。接下来就简单了,只要比较剩下的两棵白菜的重量就可以了。
试着用程序代码(如图2)模拟这样的思维方式:把三个数字放进列表,用tmp变量代表人头脑中临时存储的数据,先找出最小数,然后将其从列表中删除,接着比较剩下的两个数字即可。
● 三个生肖先后的排序
如果有人问马、鸡、兔这三个生肖哪个在先哪个在后,不是所有人都能第一时间回答上来,然而十二生肖全体的顺序,大部分人都能通过口诀背出来:鼠牛虎兔龙蛇马羊猴鸡狗猪。在背诵口诀时,特定生肖出现的次序自然而然显现了出来,所以在比较生肖大小的时候,往往要背一遍生肖口诀,哪个生肖先出现,自然就排在前面——实际上,笔者每次都是这么做的。代码如图3所示。这段程序代码的作用,就是观察哪个数字会先在数字的列表中“涌现”出来,其运行结果如图4所示。
● 三张扑克大小的排序
在整理扑克牌的时候,假设只考虑从小到大排列,人们会采用什么样的方法呢?
有两种比较常用的办法,一种是,看见相邻的扑克牌,如果顺序不对,就把它们换过来。反复执行此过程,直到所有牌排列整齐。这其实就是冒泡排序的思想了,只是人在整理扑克牌时,并不严格遵守“相邻”这一规则,交换次序的对象也是随性而为。
用冒泡排序的方法给三个数字排序,代码十分简单,如图5所示。
人们有时也使用另一种方法,因为数字从小到大排列完成后,它们所处的位置是固定的,“A”必然是在1号位,“2”必然是在2号位,所以只要抽取扑克牌,直接把它放到应处的位置上就可以了。用程序代码(如图6、图7)模拟这种方法,甚至连分支结构都不需要了,这难免让人怀疑,这真的算是排过序了吗?
从上面的各种例子能看出,仅就三个数字从小到大排列这一任务,有着许多不同的程序设计手段,足以展现出人的思维的变化多端。
当前,“计算思维”一词颇为热门,本文给出了一条比较独特的研究路径,即将计算本身作为一种工具来回溯人的思维,借助不同的计算方式,来模拟出人在不同场景和任务中的思维方式。
人的思维本身隐藏在头脑之中,难以直接观察、检验和描述,虽然当前人们主观上认为,这种模仿尚不能揭示人类思维本身(此处不考虑持强人工智能观点的学者对未来技术发展的假想),但人们往往能够判别出,某些计算机程序的运作过程更接近于哪些场景中人类完成任务的模式。即便像枚举算法,比如“在三位数中找出所有能被13整除的数字”这样的任务,乍看上去十分机械无趣,但枚举此事本身,无论是确定检查范围、匹配一致性,还是就对象进行分类(分成满足条件或不满足条件两类),都需要用到抽象的逻辑推理。这方面的思维能力,甚至不能说这是人类专属的能力,有一些抽象的逻辑推理能力在鸟类和哺乳动物的行为实验中得到了验证。可见,即便是那种很机械、很计算机式的工作过程,也与动物或人的思维方式密切相关。