第一章:
磁碟排序:對於乙個提出的問題,不要未經思考就直接給出答案。要先深入研究問題,搞清楚這個問題的特點,根據這個特點,可能有更好的解決方案。
比如:文中:最初的需求只是「我如何對磁碟檔案排序」。
我們首先想到了經典的歸併排序。
但進一步了解到排序的內容是10000000個記錄,每條記錄都是乙個7位整數,且只有1m可用的記憶體。每條記錄不相同。
第二章:
三個問題:
1、給定乙個包含32位整數的順序檔案,它至多只能包含40億個這樣的整數,並且整數的次序是隨機的。請查詢乙個此檔案中不存在的32位整數。在有足夠記憶體的情況下,你會如何解決這個問題?如果你可以使用若干外部臨時檔案但可用主存卻只有上百位元組,你會如何解決這個問題?
若記憶體足夠用則可用位圖方式。
若記憶體不夠用,可用二分查詢的方式。
2、將乙個具有n個元素的一維向量向左旋轉i個位置。例如,假設n=8,i=3,那麼向量abcdefgh旋轉之後得到向量defghabc。你只能使用1位元組的輔助變數。
先將向量abcdefgh逆序,得到hgfedcba,再以後i個位置為分割,hgfed和cba分別逆序,得到defghabc
3、給定一本英語單詞詞典,請找出所有的變位詞集。例如,因為」pots」 「stop」 「tops」相互之間都是由另乙個詞的各個字母改變序列而構成的,因此這些詞相互之間就是變位詞。
將詞典中的每個單詞都進行簽名,這樣同一變位詞類中的單詞會具有相同的簽名,然後將具有相同簽名的單詞歸攏到一起。
簽名:通過計數表示字母重複次數的方式給出。(例如:」mississippi」的簽名可能是」i4m1p2s4」)。
然後以簽名為鍵進行排序,把具有相同簽名的單詞擠壓到一行。
第三章:資料結構程式
表單字母程式設計:
例如:
作為乙個程式設計師,你應該意識到計算機從資料庫中查詢你的姓名並取回了相關資料。
但是程式該如何精確地從你的資料庫記錄中構建那個定製的web頁面呢?草率的程式設計師可能很想像下面那樣開始編寫程式:
更好的方法就是編寫乙個依賴於下面這樣的表單字母模式的表單字母生成器:
表示法$i表示記錄中的第i個字段,所以$0表示姓,等等。下面的偽碼將解釋該模式。
(這段偽碼假定字母$字元在輸入模式中寫為$$)
read field from database
loop from start to end of schema
c= next character in shema
if c != '$'
printchar c
else
c = next character in schema
case c of
'$': printchar '$'
'0'-'9': printstring field[c]
default: error("bad schema")
構造更多更好的資料結構,把資料從**中分離出來。 你的程式會更短小、精悍、易於維護、易於擴充套件。
面向過程程式設計:把資料從**中抽離出來
物件導向程式設計:把資料從**中抽離出來且把處理這個資料結構的專門**和此資料結構 繫結到一起,組成乙個類。
資料結構對軟體的乙個貢獻:將大程式縮減為小程式。資料結構還有其他許多正面的影響,包括時間和空間的縮減。增加可移植性和可維護性。
程式設計師在對空間缺乏無能為力時,往往會脫離**的糾纏,回過頭去凝神考慮他的資料,這樣會找到更好的方法。表示法是程式設計的精華。 ——fred brook 《mythical man month》
幾個原則:
1、將重複性**改寫到陣列中。
使用最簡單的資料結構——陣列——來表示一段冗長的相類似的**往往能達到最佳效果。
(例如各種if 整合到陣列中)
2、封裝複雜的結構
當你需要乙個複雜的資料結構時,使用抽象的術語對它進行定義,並將那些操作表示成乙個類。
3、讓資料去構造程式。
使用適當的資料結構去替換複雜的**,這可以使資料起到構造某個程式的效果。
(在編寫**之前,好的程式設計師通常都會通篇理解構建程式時所圍繞的輸入資料結構、輸出資料結構以及中間資料結構。)
第四章:編寫正確的程式
斷言在程式維護期間很關鍵。
保持**的簡單性通常是正確性的關鍵。
關於迴圈不變式:(還可參照《演算法導論》插入排序部分)
例如二分查詢:
二分查詢的關鍵概念在於我們總是知道如果t在陣列x[0…n-1]中的某處,那麼它必定在x的某個範圍中(我們致力於縮減這個範圍)。我們使用簡寫形式mustbe(range)表示如果t在陣列中,那麼它必定在range中。
初始化range to 0…..n-1
loop
if range is empty,
break and report that t is not in the array
計算m (range的中間位置)
用m值來縮減range的範圍
若在縮減的過程中發現了t目標值,則break,列印出它的位置。
本程式的關鍵部分就是loop invariant,即用{}括起來的部分。有關程式狀態的這個斷言被稱為不變式(invariant),因為每一次迴圈迭代的開始和結尾它都是真值(true)。
l = 0; u = n-1
loop
if l > u
p = -1; break
m= (l + u)/2
case
x[m] < t : l = m+1
x[m] == t : p = m; break
x[m] > t : u = m-1
程式驗證的基本技術是先精確指定該不變式,並在我們編寫每一行**時密切關注以保持該不變式。在我們將演算法草圖轉成偽碼時,這種技術對我們幫助極大。
(當迴圈涉及到影響不變式的語句時,要檢測此不變式是否更改。)
二叉查詢的優化:返回目標數第一次出現的位置。
l = -1; u = n
while l+1 != u
//invariant: x[l] < t && x[u] >= t && l < u
m= (l + u) / 2
if x[m] < t
l = m
else
u = m
//assert l+1 = u && x[l] < t&& x[u] >= t
p = u
if p >= n || x[p] != t
p= -1
第五章:構建腳手架
當不得不除錯乙個深深嵌入到乙個大型程式中的小演算法時,我有時會使用諸如單步除錯那樣的除錯工具來除錯該大型程式。但是,當我像上面那樣使用腳手架除錯乙個演算法時,使用printf語句通常實現要更快一些,比起複雜除錯工具來說也要更加有效一些。
我們使用斷言來陳述我們相信某個邏輯表示式是正確的。
程式設計珠璣閱讀筆記01
在此案例分析中我們可以發現,這些事實所包含的第 乙個教訓是 仔細分析小問題 有時可以帶來巨大的實際好處。在本例中,花幾分鐘的時間來仔細分析,導致了 長 度 程式設計時間和執行時間減少了乙個數量級。chunk yeager將軍 第 乙個 飛行速度超過 音速的人 使用 簡單 較少的零部件 易於維護 非常...
《程式設計珠璣》閱讀筆記03
該書的第三個大部分講述的是產品。前面的兩個部分,為第三部分打下基礎,前兩部分講述如何程式設計,以及怎樣程式設計可以是程式效率更高,效果更好,而這一部分則是將前兩部分所講述的內容應用到程式設計中去,通過實際應用講述章節 的技術所聚焦的焦點。在第三部分中,11章講述了幾個一般用途的排序演算法,12章講述...
《程式設計珠璣》閱讀筆記02
該書第二部分講述的是,效率,正如書中所說,簡單而功能強大的程式可以讓使用者高興,也不會讓程式構建者煩惱,而這就是程式設計師的終極目標,正如上一章所提到的,程式的簡練精悍才是真正重要的,而本章,作者開始講述程式效率的重要性。第6章講述了各種方法,以及他們之間如何作用,第7章講述了在早期的設計過程中所使...