背景:
从事技术工作的程序员和项目经理们往往会陷入一个个具体工程问题,感觉困难重重、前路迷茫。其实,只要投入一定时间和精力来做一些研究性的工作,掌握一些常用的问题研究工具和方法,大多数的问题都会变得清晰可解。这些研究工具和方法包括归纳、演绎、反证、分类讨论等等,这些不仅仅可以用来解数学题,还可以成为你在工作甚至生活中的得力助手。你在技术工作中遇到过怎样的问题?你在遇到问题时,能够使用系统的研究方法来应对和解决吗?2012年3月7日-2012年3月14日,我在“51CTO技术门诊”与网友进行上述前提的交流,部分问题如下。
网友wujing2126:高老师,您好!我从事网站编程方面的工作,刚参加工作不久,平时工作中对于数学逻辑方面的问题涉及到的并不是很多,平时对于一些问题的研究并不是很多,但是有一个问题我想请教一下,就是在研究过程中,总是会发现研究效率特别低,往往一个问题会困扰很长时间,我觉得会不会是因为方法有问题,请问您有什么好的关于研究问题的一些技巧么?
我:请问您有什么好的关于研究问题的一些技巧么?——大哉问!
《研究之美》里面写了很多有关研究的思路,看看会比较有用。总结起来,应该大致有几种:
1. 找关键。排除与你的真实问题无关的种种表象和干扰项,确定你要研究什么,往往是极有效果的一步,但这一步往往被人忽略了。好比你要研究为什么一个Web页面会无法加载,你就要排除很多貌似有关的问题,不要陷进去。比如,如果在IE6和非IE6的浏览器上都无法加载,就证明它不是由IE版本引起的问题,就不要在此浪费时间了。
2. 归纳。很多问题指向同一个规律,此时应该想办法一次性地加以解决,哪怕只是达到部分的解决。这是从特殊向一般的推导。
3. 演绎。从一个地方总结出来的规律,可以用在貌似不相干的别处。这是从一般到特殊的应用。
4. 反证。要证明一种规律不成立,就要想办法找到符合前提(输入)但不符合结果(输出)的反例。 有的时候,这种反例不容易找,需要花费精力思考才能构造出来。
5. 大图景。特殊问题解决不了,想想它是不是某个更大问题的一部分,而那个更大的问题可能很容易解决。类似地,一个问题解决不了,把它和另一个或另一些问题捆绑在一起,反而容易一起解决了。
大胆假设,小心求证,这是很普通的话,但却是一切研究问题的根本解决之道。只要这种假设不是乱猜一气,而是由上面说的这些方法作为基础的,久而久之,反而能锻炼出不错的研究直觉,那个境界就高了。我这里讲的还是比较抽象的了,看看书会有更具体的例子帮助你理解。
网友Caifox:高老师,您好。C++和C#哪一个的前景更广一些呢,现在的青年程序员,应该选择哪一种程序语言来做?
我:您的这个问题相信也是很多朋友想问的,但是我却觉得这个问题并非是像看起来那么重要的。我的意思是说,选择哪门语言可能并非那般重要,重要的乃是掌握数据结构和算法。无论使用哪种语言来做程序设计,说到底也是为了能够有效地表达这些数据结构和算法而已。说起来也很巧,我曾经和C++之父BjarneStroustrup和C#之父Anders Hejlsberg都有过面对面的交流,我还写过一篇和Anders Hejlsberg的访谈博客,您可以看一下,挺有意思的。
但是说语言完全不重要,那也不客观。C++和C#用在不同的领域里,前者可以直接操纵物理内存,可能在底层(系统层)用得多些,比如操作系统、编译器、游戏物理引擎等,而C#则是用于应用层多些,比如开发动态站点后台等。当然,这两者的前景都十分地广阔,可以说掌握了其中一种,一生也就受用不尽了。不过话又要说回来,无论走哪条路,只掌握语言的语法层面都是远远不够的,还是要掌握数据结构和算法这个级别才能上进。这原因不是别的,而是因为“事物的抽象都是相似的”,无论这事物是数据库还是订单会话。而程序设计的实质就是表示和动作的抽象,在这个层面上就没有什么语言之分了。
当然语言也是很有意思的,现在的选择也远不止C++和C#两种,函数式语法也是很有意思的活跃领域,有时间可以关注一下。
网友max116:高老师,您好。我数学一直不好,高数什么的也学得不怎么样。我想问在实际的开发工作中要用到哪些数学知识,又如何做到有针对性的提高呢?对数学是作为研究来看,还是作为思维锻炼的工具呢?
我:传统意义上的高等数学主要地由初等微积分、空间解析几何和线性代数组成,这几部分内容当然很重要,但却和学好计算机科学只有很弱的关系。在我看来,掌握递归技术、渐进分析、初步的平摊分析、整数和动态规划,以及非常有限的一部分数论,是比较重要的。我看过一些离散数学的教材,感觉那些内容也过分地理论化了一些,对于工作的直接贡献,可能有一定的脱节。
我在很多场合都特别地强调过掌握基本数据结构的极端重要性,这包括线性表、矩阵计算、跳表和散列表、堆、平衡二叉查找树、简单图等,这些数据结构上面构建了基本算法。不熟练地掌握这一部分数学,学习更高阶的内容无异于构建空中楼阁。如果说针对性,那末我认为针对这些内容下大功夫,应该是方向不错的。
数学离不开研究,但研究不一定是作为职业的。如你所说,作为思维锻炼的工具也不错。但问题在于,你要真的碰到问题时用数学的严格思维来去分析和解决,而不是嘴上这么说,实际上还是碰运气。数学的强大武器有两个,一个叫证明,一个叫计算。不要想当然地觉得一件事试了几次能成立就以为是规律了,要证明了才算数。遇到复杂的问题,要有耐心算到一个适当的程度,而不要仅仅靠主观的感受就下结论。很多骗子现在就是从人的直觉下手的,描述一个骗局,让人觉得风险低收益大,很多人就上了当。而在数学方面有素养的人,一般就不会惹上这样的麻烦。
以上,共勉。
网友leerobot888:高老师,您好!我是一个初级程序员,希望提高自己,尤其在数学方面。请问我该如何入手,如何提高?希望老师分享下数学学习的经验。
我:程序员的工作一般比较忙碌,有自修上进,学习更多数学内容的心,这是很值得鼓励的。
数学作为一个大的学科类目,已经是太庞大了。一开始,最好从熟悉的内容着手。而程序员每天工作相关的内容,就是数据结构和算法,这部分内容就是很好的切入点。
不要满足于已知的部分,从你看不懂的那个部分开始,才有新的收获。比如,动态数组的尺寸维护;比如,字符串的秩数组快速计算;甚至是反转单链表……最容易学习的部分,就是你已经懂得了一部分,还有一部分不懂的知识,你可以踩着坚实的基础往上走。但是无论如何,既然学习程序设计,那末最有用的那部分数学,就是算法分析。这部分内容,无论如何也是要多看看《算法导论》的。如果这个内容你都感觉太深的话,就先看看《算法技术手册》和《算法概论》(后一本可读性比较好,但是难度并不低);如果感觉很容易就可以看懂的话,就可以看看进阶的算法书,如《计算机算法的设计与分析》(难度很大,需要相当的基础)甚至《计算机程序设计艺术》(难度非常大,需要极好的数学功底,不妨先看看《研究之美》、《具体数学》)。
如果有兴趣研究研究纯粹数学的话,那末可以看看Courant的《微积分和数学分析引论》或小平邦彦的《微积分入门》;如果只是想泛泛了解和涉猎下,可以看看戈丁的《数学概观》。当然我仍然建议即使看这些书,也一样要和算法分析结合起来看。比如重点看看斯特林数用于大数估计、解析函数的泰勒展开和大O记法、生成函数的计算和应用等等。这些在纯粹数学中,只是平常的部分,但是对于学习算法的人来说,却是大部分工作的基础。当然,掌握一些随机过程也会在海量数据处理时派有很大的用场,学是学不完的了,慢慢来,一起进步吧。
网友breezy_yuan:作为开发者,往往更注重扎实算法、数据结构,操作系统等基础知识,很少有人有兴趣和耐心去研究和总结这些方法,请问研究这些东西对开发的帮助大吗?还有您是怎么喜欢上这些研究并且平衡日常的工作和研究呢?谢谢。
我:算法、数据结构、操作系统都是需要大量的基础研究投入才能有所精进的学问,几十年来,软硬件的飞速发展更多地是上世纪研究成果的应用,而真正突破性的理论研究成果却并不多。这一方面说明在研究方面产生成果的困难,另一方面当然也有很多人觉得这里面的难度很高,望而却步,能真正进入这个领域的人数较少的因素在。
所以大多数的时候,研究性的成果是以软件工具库的形式提供给普通开发者的。比如,STL里面许多关联式容器的实现是用到了红黑树的,但是普通的开发者并不需要了解实现的细节,他们只需要理解key和value的对应关系,并使用直观的语法来完成所需要的操作就可以了。这当然是好事,它降低了程序员入行的门槛。但是另一个方面来说,这也造成了开发者的惰性,大部分人都会躺在别人准备好的温床上赖着不起来,失去了自己去研究的动力。
但是有些情况下这样做就行不通了,比如,开发的环境中不能使用C++语言,需要你手工来实现key/value,又要求严格的时空性能,这时你怎么办呢?平时注意学习的同学们,这个时候就可以大显身手了!一般来说,要求严格的项目,价值也高,能搞定这样的项目,老板也会很欣赏你的。这不仅仅是一时的回报,还有可能是宝贵的机会!所以,学习是一定有机会回报给你的。
其实没有人会天生喜欢上什么,只是在钻研的过程中体会到乐趣,以及“懂了别人不懂的东西”的成就感,自然会形成良性的循环了。所以,需要的其实是一个“第一推动力”,可以想办法给自己设定一个目标,比如“我一定要看懂KMP算法是怎么回事”,然后给自己小小的奖励,“如果看懂了我就给自己买一个iPod Nano”。呵呵,只是个例子啦,不过挺管用的。
网友Wglzaj:老师,您好!我认为一个优秀的数据库管理员离不开数学,而一个好的程序员一定是数学高手,条件判断,循环遍历,检索查询等。请问在C语言�程中如何灵活运用数学中的归纳法等原理来提高自己的编程水平,一个好的程序员必须学好数学中那些内容?
我:一个优秀的数据库管理员离不开数学——你说得很对,从数据表的建立和维护,到数据库索引的优化,都离不开SQL代数,SQL语言是建立在SQL代数的基础之上的。
你的问题:在C语言�程中如何灵活运用数学中的归纳法等原理来提高自己的编程水平,一个好的程序员必须学好数学中那些内容?——不仅仅是C语言,C语言本身是图灵机的一种高阶描述,这一点和任何其他图灵完行的语言没有什么不同。因此学习语言的语法时要结合静态的内存布局,和运行时的内存变化算法来掌握语法背后所代表的语义,才算是学活学深。
程序员需要掌握哪些数学,我个人的意见是基础数据结构及其基本操作、基础算法及其时空复杂度。
更多相关内容,可以到“51CT0技术门诊”页面进一步查看:http://doctor.51cto.com/develop-252-1.html