由汉诺塔小游戏引发的思考
2014-05-09 16:50
579 查看
写在前面的话
距离上一次写Blog已经整整十月有余,之前的文章全部都随着酸甜苦辣交织在一起的记忆留在了上一家公司的内部知识管理平台里(所谓的信息安全考虑)。今天在公共平台再次开张,生活中的点点滴滴外加工作上所思所悟是最美好的体验和最值得记忆的素材,开弓没有回头箭,希望自己能有恒心坚持记录美好,留住感动。故事的缘起
三个月前,大师XueFeng在论道时谈到:scala语言的类型系统是图灵完备的,在诸多论证中最重要的一条是程序员可以借助scala的类型系统在编译期求解汉诺塔问题,大师随口问我是否可以利用C++的模板元编程能力也在编译器求解汉诺塔问题,由于本人学艺不精,向大师坦诚了自己没有能力用template求解此问题,暂时无下文。两天前,大师的追随者MengMeng给了我一份利用C++模板求解FizzBuzzWhizz问题的程序,拜读之后,若有所思,遂面机一个时辰以图破壁,乃有下文。汉诺塔问题
有三根柱子与n个大小不一的盘子,初始时,这n个盘子从大到小叠放在第一根柱子上,并且小盘子位于大盘子上面。问题是如何把这n个盘子从第一个柱子全部移动到第三个柱子上,移动时满足这样的规则:每一次只能移动一个盘子,并且满足小盘子只能在大盘子上面利用Scala类型系统推导能力求解方法
我最早看到的利用Scala类型系统求解的Blog作者是老高,在老高Blog基础上解释这个问题的博主又有不少,在所有文章里,我个人认为最通俗易懂、深入浅出的是freewind的大作,请参阅点击打开链接C++模板类型推导求解源代码
#include<iostream> using namespace std; template<int NUM, int FROM, int TO, int TRANS> struct hanio: public hanio<NUM-1, FROM, TRANS, TO>, hanio<1, FROM, TO, TRANS>, hanio<NUM-1, TRANS, TO, FROM> { hanio() {} }; template<int FROM, int TO, int TRANS> struct hanio<1, FROM, TO, TRANS> { hanio() { cout<< "Moving From "<<FROM<<" "<<TO<<endl; }; }; int main() { hanio<3, 1, 3, 2> ho; return 0; }
代码解释:
1. 有一位我记不清名字的计算机界著名前辈认为“程序=数据+算法”,上面代码的核心既不是C++也不是C++ Template, 而是算法,如果哪位看官不清楚基本的求解汉诺塔问题的算法原理,请原谅本人在此不再详述。2. 当编译器看到hanio<3, 1, 3, 2>这样的类型时,需要在各个模板类定义中找到最为精准匹配的模板以便生成具体可用的类,但是模板类定义里面可以使用其他的模板类,于是编译器不知疲倦的继续去寻找,以此类推,就这样,递归便形成了。
3. 编写一个递归程序其实就好比用数学归纳法解题,递归的终止条件就好比数学归纳法的初始假设,汉诺塔问题递归终止的条件是从某个柱子只移动一个盘子到另外的柱子上。
相关的基础知识:
C++模板基础 (C++ template fundamentals)模板特化、偏特化 (Template Specialisation, Template Partial Specialisation)
类型推导 (Template Deduction)
题目之外的思考
1. 图灵完备究竟是个什么概念?为了避免贻笑大方,我在阅读了不少相关材料以及数学推导之后还是决定将刘未鹏的博文链接到这里,这是我迄今为止所看到的最为易懂的中文论述:请参阅点击打开链接
2. 个人奇技淫巧的看法
我认为对于绝大多数程序员应该将更多的精力放在学习程序设计基本原理上,而不是过分专注个别语言的奇技淫巧,比如本文所述的汉诺塔问题C++与Scala类型系统求解,或者是拿C语言编写一个程序打印的结果是源代码自己,掌握这些问题背后的基础知识是内涵所在,前者是算法加模板知识,后者是宏。
3. 终极问题,我应该做一个什么样的程序员
这个问题困扰了我很久,至今没有明确可行的答案,一个比较理想化的版本是,做心目中的自己。一个比较务实的版本是,做一个能够Hold住眼下工作的同时又能应付未来可能变化的程序员,抛砖引玉,欢迎大家讨论。
致谢
我不想变得矫情,但是有些时候应该有的礼貌还是必不可少的,大师XueFeng的程序论道不止一次激发了我的想象力,FreeWind深厚的技术功底与优美的写作文笔刺激了我“脆弱”的神经,MengMeng同学的无私分享是压死骆驼的最后一根稻草,在此一并致以诚挚的谢意。相关文章推荐
- 由Equals()引发的对对象的引用与对象(即实例)的关系的思考
- 一道面试题引发的有关随机数的思考(7)
- Linux0.11 由进程睡眠函数sleep_on()中的堆栈变量tmp引发的思考 关于进程内核堆栈
- 链接A引发的思考
- 网络公开课《八一建军节引发的Oracle数据库思考:虚拟私有数据库》
- 各种关于ViewGroup中touch事件传递引发的思考
- 由错误ora-911引发的思考
- 关于DML命令与DDL命令引发的对事物特性的思考
- jdk安装和环境变量所引发的思考
- Sql Server之旅——终点站 nolock引发的三级事件的一些思考
- 美国两起并购引发思考:传统行业转型及创业机会何在?
- 由打开文件失败引发的思考
- 由带参数的函数main引发的——字符串指针的思考
- 由判断三一点是否在三角形内部而引发的思考.....
- 学习效率感想——博客引发的思考
- Servlet网上售票问题引发线程安全问题的思考
- JavaScript 数组循环条件自减到0时引发的思考
- 切换鼠标左右按键引发的思考(批处理、VBS、DynamicWrapper)
- long和BigDecimal引发的管理思考
- 主管一席话引发的思考