入門任意一種編程語言所必須的幾道習題


  版權申明:本文為博主窗戶(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等。

  

  漢諾塔(Hanoi Tower)

 測試

  

  漢諾塔有三個柱子,最開始在第一根柱子上按從小到大的順序放了n個盤,每次可以移動一個盤,並且只能小盤放在大盤的上面。問如何才能把這些盤從第一根柱子移到第二根柱子。

  這個基本上是學習所有語言時候學習遞歸必然要接觸的例子,實現了這個,也基本上對所學習語言的遞歸有了初步的了解。

  我們可以把問題看成是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,另外,我們可能還要考慮分數,比如下面經典題目5、5、5、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*33*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,就可以和很多其他語言產生共鳴,我們在實現某些庫的時候也會去想想別的語言是如何實現的。

 

  結束語

 

  計算機語言的學習總是循序漸進的,總之本着多思考、多對比,永遠不要讓新學到的知識形成知識孤島,而要讓所有的知識彼此緊密聯系在一起,這樣才會不斷進步,並更有創造的靈感。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM