进入梅雨季节,一周末雨水连绵不绝,空气中泛着潮湿的凉爽。这个天气最适合找个角落,安安静静地读书写字。
继续读《计算之魂》,前次读到递归,今天则了解递归地数据结构实现。递归算法的层层实现,需要保留从顶部到底部的很多中间状态,在到达最底层时,根据保留下来的状态一一回溯,直到最顶部。堆栈对这一算法需求的适配程度非常高,因为对战是一个先进后出、后进先出(LIFO)的数据结构。
拿上次的汉诺塔举例。原题中是要求将64个盘子从A柱借助T柱移动到B柱,上篇为了简单,代码实现时只输出了4、5个盘子的情况。那么回到原题,想挪动第64个盘子,就要先挪走上面的63个,具体来说,Hanoi(64, A, B, T)调用了过程Hanoi(63, A, T, B),而Hanoi(63, A, T, B)又调用了Hanoi(62, A, B, T)......,直到Hanoi(1, A, T, B),如下图所示:
最初进入堆栈的是Hanoi(64, A, B, T),放在最底下,然后是Hanoi(63, A, T, B), 放在倒数第二层,最后进来的是Hanoi(1, A, T, B),放在最顶层。最顶上的Hanoi(1, A, T, B)最先被执行,然后被清除出堆栈。一直到最底部的Hanoi(64, A, B, T)被执行,执行完毕并被清除出堆栈后,堆栈被清空,整个程序执行完毕。
堆栈这种处理事情的顺序在生活中并不多见,所以初学者理解起来会觉得有些困难。但是对于计算机来说,它在处理问题时,常常是把一个大问题从上而下分解成很多小问题,一个个拆开并解决之后,再回过头来得到整个问题的答案。堆栈能够记录这中间一步一步分解的复杂过程,而且由于最后合并的过程和一开始拆解的过程正好相反,因此它后进先出的特点很自然地将分解了的问题合并回去。
书中还给出了用堆栈实现简单计算器的例子,由于时间限制,今天就先不再多写了,感兴趣的同学可以找书来读。作为一个行业老兵,再回过头来去读这些看似基础的理论,仍然是有很多反思和收获的。