學習《數據結構》與《算法設計與分析》這兩門課程已經有一段時間了。但在設計編寫代碼時,還是不能做到遊刃有餘。怎麼說呢?平時在編寫代碼的時候不會去考慮很多。諸如:是否要用哪個數據結構?是否可以用哪個算法?之類的問題很少會在腦海浮現。原因是:當想到用哪個數據結構或者哪個算法時,往往發現實現起來很麻煩,很難,總得花不少時間去重翻課本,對自己的要求就是寫出能工作的程序就行了。久而久之也就對這樣的想法敬而遠之了。這樣編程寫的代碼無法突破順序,簡單的模式,不僅如此,代碼沒有使用很好的算法,還有一個致命的缺點:效率低下。除非特意去花時間突破這些瓶頸。我所說的遊刃有餘是:編寫代碼時,無意識地,潛意識地使用高級數據結構,使用高效算法。無需去特意要求自己,對於自己,這樣的編寫代碼不是一種要求,而是一種習慣。使用好的數據結構,使用好的算法就是理所當然的,就像吃飯,有誰不吃飯的呢?有誰編程不使用好的數據結構,好的算法呢?還有一個原因,長期以來的學習,我深深的意識到:數據結構與算法設計好比程序員的內功。掌握了內功心法,學什麼東西都快,都跟容易。就好比張無忌練就乾坤大挪移內功心法,龍爪手片刻精通,就好比周星馳韋小寶得了神龍教內功,一跳沖天。
基於以上原因,我買了《數據結構與算法分析--c語言描述》這本書,決定好好修煉我的內功。內功修煉,不比套路,需要很高的悟性,需要很有耐心,會讓你很痛苦,會花掉你很多時間。當絕不能半途而廢。
1.1 本書討論的內容
生活中的問題可以用很多種算法來解決,小規模的問題上,看不出不同算法孰優孰劣。大規模的問題,好的算法體現的優勢讓你驚歎不已,壞的算法幾天的計算才能得出的結果,用好的算法有時幾秒中就可以出來,甚至時間更短。設計算法,掌握好的算法,辨別算法的好壞,就是接下來要學習的。
1.2 數學知識複習
指數
對數
級數
模運算
證明方法:
歸納法:
第一步:證明基準情形,一般是顯而易見的,可直接得出的。
第二步:進行歸納假設,假設定理對直到某個有限數k的所有的情況都是成立的。然後使用這個假設(必須),證明定理對於下一個值(通常爲k+1)也是成立。也就證明了在k是有限的情況都成立。
反例法:
隨便舉出一個不符合的情況即可推翻定理。
反證法:
通過假設定理不成立,然後證明該假設導致某個已知的性質不成立,寵兒說明原假設是錯誤的。
1.3 遞歸簡論
遞歸的四條基本法則:
(1)基準情形。(必須存在,無須遞歸就能解出)
(2)不斷推進。(遞歸求解的方向:每次遞歸都朝着基準情形接近一步,知道最後到達基準情形得出結果)
(3)設計法則。(假設所有遞歸都能運行,設計遞歸程序時沒有必要知道簿記的細節)
(4)合成效益法則。(在求解一個問題的同一實例時,切勿在不同的遞歸調用中做重複性的工作(才能高效益),用動態規劃可以滿足結果的重用,不重計算)
- // 遞歸打印正整數
- void PrintOut(unsigned int N)
- {
- if (N >= 10)
- {
- PrintOut(N/10);
- }
- printf("%d", N%10);
- }
練習
1.8 2^100(mod 5)是多少?
2^1 (mod 5) = 2^5 (mod 5)
(2^1 * 2^4) (mod 5) = (2^5 * 2^4) (mod 5)
2^5(mod 5) = (2^1 * 2^4)(mod 5)
2^1(mod 5) = (2^5 * 2^4)(mod 5)
...
2^1(mod 5) = 2^5 (mod 5) = 2^9 (mod 5)...2^(1+4k) (mod 5) = 2
2^2(mod 5) = 2^6 (mod 5) = 2^10 (mod 5)...2^(2+4k) (mod 5) = 4
2^3(mod 5) = 2^7 (mod 5) = 2^11 (mod 5)...2^(3+4k) (mod 5) = 3
2^4(mod 5) = 2^8 (mod 5) = 2^12 (mod 5)...2^(4k) (mod 5) = 1
2^100(mod 5)= 1