版權申明:本文爲博主窗戶(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,就能夠和不少其餘語言產生共鳴,咱們在實現某些庫的時候也會去想一想別的語言是如何實現的。
結束語
計算機語言的學習老是按部就班的,總之本着多思考、多對比,永遠不要讓新學到的知識造成知識孤島,而要讓全部的知識彼此緊密聯繫在一塊兒,這樣纔會不斷進步,並更有創造的靈感。