《時間復雜度的計算》
一:為什麽要計算時間復雜度?
- 一說起時間復雜度,就和算法扯上了關系,那麽就有了一個問題,在我們寫好了一個算法之後,如何測試這個算法的好或者不好呢?
- 事後統計法,指的是在算法完成之後,通過實際的運行來檢驗算法的好壞。但是,這樣也有兩個致命的缺點
- 如果算法不行,那麽我們實際運行圖了個什麽?
- 機器性能一會好一會不行怎麽破?
- 因為 事後統計法 的不靠譜,所以我們采用了 事前分析 的方法,也就是我們說的 時間復雜度。
- 不過因為是事前統計,其算法本身也並沒有通過實際環境的檢驗。
- 所以,時間復雜度,其實只是一個度量
- 也就是說只是給了你一個尺子去量一下這個算法的耗時,不是這個算法實現以後真的會耗時多少,也不是兩個不同的算法的耗時比例真的可以這麽比。
二:時間復雜度的定義?
- 語句執行次數 T(n) 是問題規模 n 的函數
- 繼而分析 T(n) 隨著 n 的變化並確定 T(n) 的量級
- 記做 T(n) = O(f(n)), 表示隨著 n 的增大,時間的增長率 和 fn 增長率相同
- 一般用 O() 表示,也稱 大 (O) 記法
- 簡單來說,記住這個公式 f(n) = n
三:如何計算算法的時間復雜度?
- 推導大 O() 計數法
- 用常數 1 來代替 運行時間的加法常數
- 在修改後的運行次函數中,只保留最高階
- 如果最高階存在且不是1,則去除這個項相乘的常數
- 下面來嘗試如何計算時間復雜度
四:常數階O (1)
-
<?php $sum = 0; // 執行一次 $n = 100; // 執行一次 $sum = (1 + n) * n/2; // 執行一次 print_r($sum); // 執行一次
- 按照定義,這個算法的運行次數是 f(n) = 4,
- 在保留最高階時,發現這個算法也沒有最高階,所以這個算法的時間復雜度為 O(1)
-
<?php // 如果執行10次呢 $sum = 0; // 執行一次 $n = 100; // 執行一次 $sum = (1 + n) * n/2; // 執行一次 $sum = (1 + n) * n/2; // 執行一次 $sum = (1 + n) * n/2; // 執行一次 $sum = (1 + n) * n/2; // 執行一次 $sum = (1 + n) * n/2; // 執行一次 print_r($sum); // 執行一次
- 事實上無論 n 為多少,都是時間恒定的算法,也是為常數階 O(1)
五:線性階O (n)
-
<?php $n = n; foreach ($n as $v) { // 時間復雜度為 O(1) 的序列 }
- 按照定義,這個算法的運行次數是 f(n) = n, 根據我們的 大 O 推導算法,保存最高階的 1,
- 也是為線性階 O(n)
六:對數階O (logn)
-
<?php $count = 1; while ($count < n) { $count = $count * 2; // 時間復雜度為 O(1) 的序列 }
- 由於 count 每次 X2 ,有多少個 2 相乘後,便會退出循環。
- 由 2x=n 得到 x = log2n
- 對數階O (logn)
七:平方階O (n2)
-
<?php foreach ($n as $v) { func($v); } function func () { for ($i = 0; $i < n; $i++) { // 時間復雜度為 O(1) 的 } }
- 外層調用了一個循環,循環 n 次去執行 func 函數
- func 函數內部又執行一次循環輸出
- 也就是說,這個算法一共執行了 f(n) = n2 次
-
// 等價於 <?php foreach ($n as $v) { for ($i = 0; $i < n; $i++) { // 時間復雜度為 O(1) 的 } }
- 也就是 平方階O (n2)
七:時間復雜度耗時大小排列(越小越好)
- O(1) < O(logn) < O(n) < O(nlogn) < O(n2) < O(n3) < O(2n) < O(n!) < O(1) < O(nn)
- 一般超過 O(n2) 的,時間太長,就不做計算了,也就是說,一個算法,最長耗時不能超過 O(n2)
《時間復雜度的計算》