要学好计算机,当然要学习编程。听说到“程序=算法+数据结构”,我也到图书馆找算法和数据结构的书来看。当时,这些书也的确都看下去了,里面也有很多图,看起来倒也不难,读书笔记也记了一些。但显然是囫囵吞枣一知半解,基本属于知道有这些数据结构,至于为什么弄这么多数据结构,这个跟程序有什么相关,为什么说“程序=算法+数据结构”,而又有人说算法和数据结构是跟你使用什么语言不相干的。我当时也不明白,上关于编程的课,写出来的程序好像做不了什么复杂的事情,作业大体还是计算个人所得税或者学生成绩统计之类的。
真正在编程方面开始入门,得益于我的导师,郭嵩山教授。郭老师多年来一直致力于在广东省普及和开展青少年信息学奥林匹克竞赛,从小开始培养中小学生计算机编程能力。在大学校园内,也积极组织和推广程序设计竞赛,鼓励大家动手编程,而不只局限于“纸上谈兵”。这些活动在计算机系,乃至整个学校形成一个动手学习编程的良好氛围,推动了程序设计学习的教学。当时,我抱着试一试的想法去参加学校的程序设计比赛。比赛中的问题一般都有一定的应用背景,涉及生活的方方面面,让你觉得自己可以写程序解决实际的问题。实际的问题抽象出来的题目,比书本中单纯的理论对于初学者来说更切近生活,也更有趣。通过动手解决这些问题,我可以体会到书本中知识的“所以然”。学习的理论知识能帮助我解决这些问题,而解决这些问题又引导我去学习新的知识。另外,解决问题的过程在思考方式上更加自然,我可以“从简单的开始动手”。
比如,为了寻找一个问题的答案,我用“穷举”的方法,所有变量的各种可能都组合考虑一遍。变量很少的时候,我可以用for语句写几重循环。但,如果变量数目很多,假如有30个变量,那么我没有办法去写30重循环。这个时候,我就开始改用本质上没有变化的“递归”程序来实现,30重循环就变成了递归搜索30层。递归程序如果很慢,就去考虑在“搜索”的过程中“剪枝”,去掉不必要考虑的分支,节省解决问题的时间。如果某一个分支已经被解决了,那就没有必要多次去搜索这个分支。在第一次搜索这个分支的时候,记录下我们感兴趣的信息,以后当再次需要搜索这个分支的时候,已经可以从记录中得到关于这个分支的我们感兴趣的信息,这就是“记忆化搜索”。在问题的搜索树中,分支如果经常多次存在,而搜索一个分支可以转化为搜索它的若干个子分支,那么把分支的情况看成一个“状态”,而分支跟子分支之间的关系就是“状态转换”,刚才通过使用“记忆化搜索”的方法记录每个分支(状态)的情况,从而避免搜索重复的解空间的思路,其实就是“动态规划”的思路。
经过动手实践,这些“深奥”的概念变得“理所当然”。我开始进步,并通过计算机这位“听话的朋友”来帮我做很多我想做而做不了的事情。在郭老师的努力下,越来越多像我一样的同学开始动手编程,而不是以传统的深究语法的方式学习程序设计。郭老师也由于在组织和开展程序设计竞赛方面做出杰出的贡献,于今年获得首届ACM/ICPC优秀教练奖。
回想起这些年来学习编程的经历,我觉得,要学好编程,重点得动手去实践。哪怕从一个简单的问题开始,从一个简单的方法开始。
“献给老师,我的编程之路”系列文章