時間複雜度(time complexity)
假設兩位朋友都答應幫你把一疊考卷按字母順序排好。一位一分鐘排完一百張;另一位卻要一小時。知道誰排一疊比較快其實沒什麼用。你真正想知道的是:當這疊變大時,他們各自慢下來的方式如何——把考卷數量加倍,工作量是加倍、變四倍,還是直接爆炸?時間複雜度研究的正是這件事。它不是某台筆電上的牆上時鐘秒數,而是當輸入變大時,一個程序所花的步數如何成長。
我們用一個機器模型把它講精確,通常是圖靈機(那本你能讀、能擦、能重寫的無盡筆記本)。一台機器的時間複雜度是一個函數 T(n):對大小為 n 的輸入而言,T(n) 是這台機器在停機前所做的最大步數,取遍所有該大小的輸入。計步數而非計秒數,讓我們擺脫任何一台電腦的快慢;而以輸入大小 n 當變數,則讓我們用單一條成長曲線(例如 T(n) = 3n^2 + 5n + 2)一次描述整個輸入家族。
時間複雜度之所以重要,是因為它是效率的量尺。兩個演算法可以都正確、都對每個輸入停機,但其中一個幾秒內解完一個實際問題,另一個卻可能等到太陽燒盡都還在跑。我們幾乎總是回報最壞情況時間,並用大 O 記法描述它,只保留主導的成長項,因為那才告訴我們一個方法是否能隨規模擴展。整個複雜度理論,就建立在把這種直覺變成可以證明的東西之上。
掃過一串 n 個數字一次以找出最大值,約需 n 次比較,所以它的時間複雜度大約是 T(n) = n,寫成 O(n)。把 n 個數字兩兩比較以找出最接近的一對,約需 n^2/2 次比較,所以 T(n) 是 O(n^2)。對一百萬個項目的清單,前者做一百萬步;後者約做五千億步。
同樣的輸入、兩種演算法:決定哪個能在大規模下使用的是成長率,而非常數。
時間複雜度描述成本如何隨輸入大小成長,而非你機器上的實際秒數;更快的電腦會改變常數,卻永遠改變不了那條成長曲線。