1968-KnuthTAOCP與演算法分析#
案件摘要#
1968 年,Donald Knuth 在 Addison-Wesley 出版《The Art of Computer Programming》第一卷,為一片混亂的演算法世界建立了第一部系統性的教材。這部從 1962 年就開始撰寫的巨著,不只收集演算法,更把「分析演算法」變成一門有嚴格數學基礎的學科。 Knuth 以 MIX 虛擬機作為中立的硬體基準,以大 O 記法刻畫演算法的增長率,以精密的文獻編號系統追溯每個想法的源頭。這樁「案子」的真相是:程式設計不只是工藝,而是一門可以被證明、被測量、被傳承的藝術。
前因 -- 為什麼會有這個案子#
- 1960 年代電腦科學快速擴張,但演算法研究碎片化:新演算法散落在期刊、報告與口耳相傳中,沒有系統性的教材。
- Knuth 在 Caltech 攻讀博士時研究編譯器(他的論文是關於組合方法的分析),深刻體會到「分析一段程式的效能」需要嚴謹的數學工具。
- Knuth 立志寫一部「程式設計的聖經」:不只教人怎麼寫,更要解釋為什麼這樣寫是對的、有多快、還能多快。
- 當時的效能分析多半靠實測與直覺,缺少像數學那樣「定理—證明」的傳統;大 O 記法在數學界已存在(Bachmann 1894 首次使用),卻從未在演算法研究中被系統化使用。
- 撰寫教材需要一個中立的機器模型:不同廠牌電腦差異太大,Knuth 於是設計了 MIX 虛擬機——一台不存在的、理想化的電腦。
線索與推理 -- 數學式、程式、理論#
線索一:演算法分析的正式化#
Knuth 在 TAOCP 中確立了三種成本刻畫的區別:
- 最壞情況(worst case):保證的上界,是工程承諾。
- 平均情況(avg case):對輸入分佈取期望值,Knuth 用機率論大量計算此類成本。
- 最佳情況(best case):多半只有理論趣味。
以快速排序為例(比較次數):
線索二:大 O、大 Omega 與大 Theta#
Knuth 系統性地使用了大 O 記法,並在 1976 年的論文〈Big Omicron and big Omega and big Theta〉中正式化整套記號,主張大 O 只描述上界,需要 Omega 與 Theta 來精確表達「恰好這個量級」:
大 O 的源頭是數學家 Paul Bachmann(1894 年《Die Analytische Zahlentheorie》),經 Edmund Landau 推廣於解析數論;Knuth 把它帶進演算法的世界,成為電腦科學的通用語言。
線索三:MIX 虛擬機#
TAOCP 的所有演算法都以 MIX 組合語言寫成:一台假想的電腦,有明確定義的指令集、記憶體與暫存器。這使演算法的分析完全獨立於硬體——後來 Knuth 又設計了 64 位元的 MMIX(1999)接替它。
線索四:文獻編號系統#
TAOCP 的引用風格(如 [Knuth 68])與章節編號(如 5.2.2 節)成為電腦科學文獻的標準範式;Knuth 堅持追溯每個演算法的原始出處,讓這部書同時是一部科學史。
線索五:實測對照——O(n log n) vs O(n²)#
以下 Python 程式實測兩種排序演算法的增長曲線,驗證「量級」的意義:
import random, time
def bubble_sort(a): # O(n^2)
a = a[:]
n = len(a)
for i in range(n):
for j in range(n - 1 - i):
if a[j] > a[j + 1]:
a[j], a[j + 1] = a[j + 1], a[j]
return a
def merge_sort(a): # O(n log n)
if len(a) <= 1:
return a[:]
m = len(a) // 2
L, R = merge_sort(a[:m]), merge_sort(a[m:])
out, i, j = [], 0, 0
while i < len(L) and j < len(R):
if L[i] <= R[j]:
out.append(L[i]); i += 1
else:
out.append(R[j]); j += 1
return out + L[i:] + R[j:]
print(f"{'n':>8} {'bubble(ms)':>12} {'merge(ms)':>12} {'ratio':>8}")
for n in [500, 1000, 2000, 4000]:
a = [random.randint(0, 10**6) for _ in range(n)]
t0 = time.perf_counter(); bubble_sort(a); t1 = time.perf_counter()
t2 = time.perf_counter(); merge_sort(a); t3 = time.perf_counter()
tb, tm = (t1 - t0) * 1000, (t3 - t2) * 1000
print(f"{n:>8} {tb:>12.2f} {tm:>12.3f} {tb/tm:>8.1f}")
理論預測:n 加倍時,氣泡排序時間約變 4 倍(O(n²)),合併排序約變 2.2 倍(O(n log n))。執行程式即可看到增長率吻合理論——這正是 Knuth 主張的「分析先於實測」。
結案 -- 後果與影響#
- 演算法分析成為一門學科:1974 年 Knuth 獲圖靈獎,表揚他「對演算法分析與程式設計語言設計的重大貢獻」。
- TAOCP 至今未完:1973 年 Vol. 3(排序與搜尋)出版,2011 年 Vol. 4A(組合演算法)出版,全書規劃七卷;KMP 字串匹配演算法(Knuth、Morris、Pratt)誕生於此計畫,1977 年正式發表。
- 文學編程(literate programming,1984):Knuth 為寫作 TAOCP 而發展的程式撰寫哲學,主張程式應如文學作品般為人類而寫。
- TeX 排版系統的副產品:Knuth 為了排出完美的 TAOCP 而發明 TeX,如今是學術排版的標準。
- 「演算法是藝術」的哲學:美(優雅)與真(正確、高效)並重,影響了整個電腦科學的教育傳統。
關鍵人物與文獻#
- Donald E. Knuth:《The Art of Computer Programming》的作者,1974 年圖靈獎得主,史丹佛大學教授。
- Paul Bachmann:大 O 記法的數學源頭(1894);Edmund Landau 將其推廣於解析數論。
- James Morris、Vaughan Pratt:KMP 演算法的合作者。
主要文獻:
- Knuth, D. E. (1968). The Art of Computer Programming, Vol. 1: Fundamental Algorithms. Addison-Wesley.
- Knuth, D. E. (1973). The Art of Computer Programming, Vol. 3: Sorting and Searching. Addison-Wesley.
- Knuth, D. E. (1976). "Big Omicron and big Omega and big Theta". ACM SIGACT News, 8(2), 18–24.
- Knuth, D. E. (1977). "Fast Pattern Matching in Strings". SIAM Journal on Computing, 6(2), 323–350.(與 Morris、Pratt 合著)
- Knuth, D. E. (1984). "Literate Programming". The Computer Journal, 27(2), 97–111.
- Knuth, D. E. (2011). The Art of Computer Programming, Vol. 4A: Combinatorial Algorithms, Part 1. Addison-Wesley.