化整为零,变繁为简

IT商界

  很高兴能和读者朋友们聊了这么多期的算法,到本期为止我们的算法演义栏目也要告一段落了。但朋友们研究学习算法不会就此结束,所以我想利用最后一期,结合我的一些实际经验来谈谈算法的学习。

  记得大一学C语言的时候,老师曾经布置过一道题,是要找出整数1到1000中的所有质数。为了解决这道题,我和我的一个好朋友在网吧里泡了近一个小时才勉强把题目给做完。在那次,笔者知道了使用子函数的好处。刚开始,出于对自己逻辑思维能力的自信,我们把所有的代码全部写在了main函数里。当调试软件的时候发现结果不对,但面对100多行包含着两个嵌套FOR循环和一堆条件判断语句的程序代码(现在看来是小儿科),我们真是有点束手无策。后来仔细地理了一遍解题思路,并把判断一个数是不是质数的程序部分提取出来作为一个单独的子函数,很快我们就找到了问题所在。在算法设计的思路里最基本的就是“化整为零,变繁为简”。像上面求质数的题目是比较简单的。如果遇到一些复杂的问题,我们首先要考虑如何将问题转变成一些我们熟悉的简单问题,再构建一些子函数来解决这些简单问题,最后把这些子函数组合起来求解就可以了。

  在前面的算法演义栏目里,我们经常使用到递归函数。可以这么说,递归函数是学习算法的一项必备的基本功。关于如何真正掌握好递归函数技术,除了实践还是实践。这里也不想多谈递归函数本身,而是谈谈在递归函数使用中的变量问题。在使用递归函数的时候,我们有时会定义一个全局的数组来存储函数调用中的一些过程量。对于递归条件不复杂、递归层数不多的情况,我们一般还能比较清楚地判断这些全局的数组是否足够大,会不会出现越界。但对于一些递归条件复杂、递归层数比较多的情况,我们就往往吃不准了。而这样的问题又常常被我们所忽视,带来的结果也是很严重的。笔者就见过一个新学编程的朋友用了整整半天的时间才在别人的提醒下找到他的程序中递归过程中的全局数组越界问题。他当时用了很长时间找不出问题的主要原因,就是在不同的输入条件下,并不是每次都会越界的。他没想到在一些特殊条件下由于递归的层数较多,而造成越界的错误。我们在学习算法解决实际问题的时候,一定要学会如何找出问题的特殊情况,并以此考察算法是否正确有效。

  另外笔者想说的是,算法的学习不应该是孤立的。这里要特别指出的是《数据结构》知识的学习对算法的学习是很重要的。在解决问题的时候,不同数据结构的确定将可能左右算法设计的复杂程度。而一些特殊的数据结构更是和一些特殊的应用紧密地联系在一起的。例如栈的概念就是专门针对后进先出的情况需要而专门设计的。笔者曾和一个学编程不到半年的朋友分别编写一个算24点的小程序。自己很快就完成了,但我的朋友却几乎没有什么进展。他在经历了近一个小时的困惑后,他放弃写这个程序了。在看过我的程序之后,他说,他的思路是和我一样的,但由于他不知道用什么样的数据结构来储存相关数据,所以感觉自己无从下手。笔者当时就建议他去好好学习一下《数据结构》。我想遇到这样问题的朋友可能还不少。

  要说的东西还很多,但我想还是留给大家在实践中去慢慢体会和总结吧。也祝大家都能享受到编程中的乐趣!