版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖。如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/11073938.html 做者:窗户 QQ/微信:6679072 E-mail:6679072@qq.com
每当学习一门计算机语言,咱们也要作一些练习以便逐步熟悉。随着咱们对这种编程语言自己支持的抽象手段理解的过程,如下这些问题,基本能够在几乎每门编程语言学习的过程当中完成,这些语言能够包含但不限于C、C++、Shell、awk、Python、JavaScript、Java、Scala、Ruby、Lisp(Common Lisp、Scheme、Clojure)、Prolog、Haskell等。html
汉诺塔(Hanoi Tower)算法
汉诺塔有三个柱子,最开始在第一根柱子上按从小到大的顺序放了n个盘,每次能够移动一个盘,而且只能小盘放在大盘的上面。问如何才能把这些盘从第一根柱子移到第二根柱子。sql
这个基本上是学习全部语言时候学习递归必然要接触的例子,实现了这个,也基本上对所学习语言的递归有了初步的了解。编程
咱们能够把问题当作是Hanoi(1->2, 3, n),符号解读为把n个盘从1号柱移动到2号柱,剩余一个柱子是3号柱。微信
很容易把这个大问题拆成三个小问题:编程语言
Hanoi(1->2, 3, n) => Hanoi(1->3, 2, n-1), Hanoi(1->2, 3, 1), Hanoi(3->2,1, n-1)函数式编程
也就是先把最上面n-1个盘从1号柱移动到3号柱,再把最大的盘从1号柱移动到2号柱,最后把最3号柱的n-1个盘移动到2号柱,函数
因而就达到了递归的效果。学习
因数分解/整系数多项式因式分解(factorization)测试
因数分解,是将输入的正整数分解为各个质数的乘积,好比:
$300 = 2^{2}\times{3}\times{5^{2}}$
因数分解普通状况下的算法并不复杂,只须要一个简单的初等数论证实便可。
而整系数多项式因式分解可能比上述还要复杂不少,好比:
$2x^{6}+7x^{5}+13x^{4}+15x^{3}+11x^{2}+5x+1 = (x+1)\times(2x+1)\times(x^{2}+x+1)^{2}$
这个不管是面向过程仍是面向对象仍是函数式编程等都值得好好作一作,若是能够,也能够尝试尝试Galois域的多项式环内的分解。
质数表(prime number list)
质数表也是一个合适的程序,可使用好几种方法。
最简单的,咱们能够依次从2开始判断每一个数,对于每一个数N判断$2\sim{N-1}$是不是其约数,若是其中没有它的约数,则为质数。
固然,上述能够提升效率,咱们知道对于任何一个正整数,若是是合数,则必定存在一个整数约数小于自身的平方根。因而咱们的判断从$2\sim{N-1}$缩到$2\sim\sqrt{N}$。
再往上进一步,咱们寻找$1\sim{N}$中的质数能够归结于寻找$1\sim\sqrt{N}$的质数。因而,咱们这就能够引入一个递归。
另外,还有各种筛法再也不细讲,能够自行google。
从而以上能够从各个角度来熟悉你所学习的编程语言。
排列/组合(permutation and combination)
组合数学的相关知识应该在中学就已经学过,咱们经过加法原理和乘法原理(实际上乘法原理也是由加法原理推出)推出了排列/组合的世界。
这里,咱们能够尝试着去写一个集合的全部排列/组合。
好比$\{1,2,3\}$的全部排列有$\{1,2,3\},\{1,3,2\},\{2,1,3\},\{2,3,1\},\{3,1,2\},\{3,2,1\}$,全部两个元素的组合有${1,2},{1,3},{2,3}$。
有不少方法实现输出一个集合的全部排列组合:
首先,不少语言都有相关的库支持排列组合,好比Python的itertools库,不少时候正式写程序仍是直接用库的。
好比$\{1,...n-1\}$的全部排列到$\{1,...n\}$的全部排列存在一个递归,组合也相似。
再者,咱们能够用字典排列依次输出所须要的排列/组合,只是如何找到下一个稍微大一点的排列/组合须要一点点技巧。
而后,咱们还能够用数与每一个排列/组合一一对应,理论上有各类对应方法。
甚至,咱们能够基于交换来依次输出全部的排列/组合,固然这里须要一些抽象代数知识。
总之,咱们有各类实现排列/组合。
生命游戏(Conway's game of life)
生命游戏是1970年Conway的发明。
MxN的图里,全部的格子都带有一个状态,为生/死。
每一次整张图都有一个状态转换,每个格子都要看周围8个格子生/死的个数。
下一代全部格子状态由如下规则肯定:
1.若是周围有生命格子的数目小于2,则下一代这个格子状态为无生命(解释为太孤单)。
2.若是周围有生命格子的数目大于3,则下一代这个格子为无生命(解释为周围生命太多,资源消耗厉害)。
3.若是周围有生命格子的数目等于2,则下一代这个格子的状态继续保持当前的状态。
4.若是周围有生命格子的数目等于3,则下一代这个格子的状态为有生命。
24点(Count 24 points)
咱们小的时候基本都玩过24点,就是4张牌使用加减乘除计算出24。
这个用程序实现是有点挑战的,咱们考虑如何遍历全部的可能,而后依次算出来,看是否等于24,另外,咱们可能还要考虑分数,好比下面经典题目五、五、五、1,计算方法是(5-1/5)*5。
再者,咱们要按照日常的使用习惯,考虑把多余的括号去掉,好比((a*b)-c)/d其实应该是(a*b-c)/d。
另外,咱们要考虑是否有结构等价,好比a*b+c*d和d*c+b*a,咱们如何判断并只保留一种。
以上面的为例,能够有不少答案,好比2*8+3*3, 3*3+(8*2), 3*8*(3-2), (3-2)*(8*3), (3*8)/(3-2),(2+3/3)*8, (3/3+2)*8...但咱们只考虑计算结构的惟一以及去掉多余括号,合理的只剩下四个答案:2*8+3*3, 3*8*(3-2), 3*8/(3-2), (2+3/3)*8。
固然,咱们还要考虑更多的牌,更多的运算来计算任意数字。总之,24点这个问题或许不是那么容易,在某些语言下的实现尤为有技巧性。
自输出程序(Quine)
解释一下,所谓自输出程序(Quine),就是程序的输出和程序的代码如出一辙,直接用哲学家Quine命名。
这样的程序也须要写?怎么感受是在学习写病毒呢?
病毒的确可能须要自输出这样的技术,可是技术这个东西自己就是双刃剑,手术刀是用来救人的,但它依然能够拿来当凶器。
每一种编程语言只要是图灵等价的(固然,其实这个条件很基本),就能够经过不动点存在定理推出Quine是必定存在。记载中,上世纪60年代诞生了第一个Quine,用Atlas Autocode编写。
对于Scheme,可能的最短的Quine以下:
((lambda (x) `(,x ',x)) '(lambda (x) `(,x ',x)))
标准库的部分实现
思考所学语言的一些标准库的实现,也是提升的重要手段。好比C++的STL,咱们在学习C++的时候能够去思考STL多是如何实现的,这样颇有助于对C++面向对象、泛型(经过模板实现)的理解。
而且,不少时候库的实现同样的语义有多种实现方式,咱们能够考虑各类实现方式的不一样。好比Scheme这样一种数据、过程彻底混在一块儿的语言,不少基本函数有很是夸张的彻底不一样的实现。
若是Scheme、Common Lisp、Clojure这几种Lisp前后学习,也能够结合在一块儿,对比着学,想一想另一种是如何实现的。几种Lisp毕竟仍是兄弟关系,有很大的类似,这种类似甚至能够扩展到同一编程范式的不一样语言之间,它们依然有不少能够相通的地方,这些均可以对比关联。好比两种从设计一开始就冲着多范式支持而去的JavaScript、Python,就能够和不少其余语言产生共鸣,咱们在实现某些库的时候也会去想一想别的语言是如何实现的。
结束语
计算机语言的学习老是按部就班的,总之本着多思考、多对比,永远不要让新学到的知识造成知识孤岛,而要让全部的知识彼此紧密联系在一块儿,这样才会不断进步,并更有创造的灵感。