分析巢狀迴圈
巢狀迴圈——迴圈裡套迴圈再套迴圈——是大多數多項式執行時間的來源,也是大多數分析錯誤的來源。「兩個迴圈就是 n^2、三個就是 n^3」的直覺是個不錯的初步猜測,但錯得夠頻繁,你應該總是檢查,因為真實次數取決於內層的界與外層索引如何關聯。
當各界互相獨立時,相乘是對的:「for i = 1 到 n: for j = 1 到 n: O(1)」跑 n 乘 n = n^2 個內部步,故 Theta(n^2);再加第三個獨立迴圈就是 Theta(n^3)。但當內層的界依賴外層索引時,你必須求和,而非只是相乘。經典的「for i = 1 到 n: for j = i 到 n」做 (n) + (n-1) + ... + 1 = n(n+1)/2 個內部步——仍是 Theta(n^2),但只因為這個三角形和恰好是 n^2 的一半;那個 1/2 的倍數被大O藏起來了。依賴性真正咬人之處,是像「for i = 1 到 n: for j = 1 到 i*i」這種,它加總 1 + 4 + 9 + ... + n^2 = Theta(n^3),而非粗心一瞥可能猜的 Theta(n^2)。
可靠的程序:把總數寫成巢狀的和(對 i 求和、其中對 j 求和、其中是內部成本),然後由內而外用標準級數公式計算。這把任何巢狀迴圈,無論界如何交織,轉成單一封閉形式,你可以從中讀出階。誠實的陷阱是反射性的相乘:「k 個巢狀迴圈」只有在每個迴圈獨立地跑 Theta(n) 次時才是 Theta(n^k);依賴資料或索引的界,可能讓真實答案更小,或在內層界成長時更大。
「for i = 1 到 n: for j = 1 到 n: for k = 1 到 n: 做 O(1)」有三個獨立迴圈,故 n 乘 n 乘 n = Theta(n^3):這是課本矩陣乘法的成本。但「for i = 1 到 n: for j = 1 到 log(i)」加總 log(1) + log(2) + ... + log(n) = log(n!),由斯特林公式為 Theta(n log n),遠少於快速一瞥所暗示的 n^2。
只在界互相獨立時相乘;否則寫出巢狀的和並計算它。
「k 個迴圈等於 n^k」只在每個迴圈獨立地跑 Theta(n) 次時成立。依賴索引或資料的內層界,可能讓真實階更小「或」更大;務必以求和來確認。