1. 程式人生 > 其它 >資料結構時間複雜度_白話資料結構和演算法02:3分鐘搞明白,什麼是大O時間複雜度,如何計算大O時間複雜度...

資料結構時間複雜度_白話資料結構和演算法02:3分鐘搞明白,什麼是大O時間複雜度,如何計算大O時間複雜度...

技術標籤:資料結構時間複雜度

關注公眾號:程式設計師成長軟技能 。日拱一卒,功不唐捐!

前文總結中說到:資料結構和演算法主要是解決如何低成本(少儲存空間&少查詢、寫入時間)的操作資料的問題,也就是要在能解決問題的前提下,“少空間”和“少時間”的解決問題。那麼如何比較不同方法的優劣,也就是如何比較不同方法使用空間的大小和執行時間的長短呢?常用方法有兩種:事後統計法和事前估演算法。

事後統計法

所謂事後統計法,就是執行演算法後,統計演算法執行的時間和使用的記憶體空間。這種方法有時候也是可用的,但存在以下缺點:

  • 需要先編寫不同的演算法,然後統計比對,浪費開發人力和時間成本
  • 演算法依賴的執行環境以及環境的狀態,可能會影響到演算法的效果
  • 測試資料準備不當,比如量太小,高效率演算法的效果可能體現不出來

事前估演算法

由於上邊所述“事後統計法”的缺點,所以需要有個不需要執行程式碼,甚至不需要編寫程式碼(使用虛擬碼),也不用準備測試資料,就可以事前粗略估算的方法。而演算法的優劣,主要是從所佔用的「時間」和「空間」兩個維度去考量。
時間維度:指執行當前演算法所消耗的時間,通常用「時間複雜度」來描述。
空間維度:指執行當前演算法需要佔用的記憶體空間,通常用「空間複雜度」來描述。
所以,這種事前估演算法就是是下邊所要說的,時間複雜度、空間複雜度估演算法。

時間複雜度

站在CPU的角度看,演算法的每段程式碼都執行在"取數-計算-寫數"的操作,雖然每個操作的具體執行時間不盡相同,但為了方便估計,我們假設每行程式碼的執行時間都是一樣的,在此假設下,演算法的執行總時間就和執行程式碼的行數成正比了。那麼,如何計算執行程式碼的行數呢?

執行行數計算方法

示例1:計算1-100所有數字之和, 我們設計兩種演算法:

演算法1

1    public int getSum1(int n ){
2        int sum=0;
3        for (int i = 1; i < n ; i++) {
4            sum += i;
5        }
6        return  sum;
7    }

演算法2

1    public int getSum2(int n ){
2        int sum = (1+n)*n/2;
3        return  sum;
4    }

如上,兩種演算法都可以達到求1-100所有數字之和的目的,但兩種演算法執行的程式碼行數是不同的。演算法1編寫程式碼一共7行,但是因為3、4、5因為迴圈的原因會執行n遍,所以執行程式碼行數一共是4+3n。演算法2編寫程式碼一共4行,並且是順序沒有迴圈的執行,所以執行程式碼行數和方法引數n沒有關係,一共是4行。從該例中可以總結如下計算方法:

  1. 非迴圈、分支情況:使用加法,即將順序程式碼行數和分支執行相關程式碼行數加和
  2. 迴圈情況:使用乘法,執行行數一般和資料量n有關係,即將資料量n和迴圈內的執行程式碼行數相乘(多層迴圈,累乘)

大O複雜度表示法

從示例1可以看出,執行程式碼行數與資料量n存在某個關係函式,比如叫做執行行數公式,此時演算法1執行行數公式是:f(n)=4+3n,演算法2執行行數公式是:f(n)=4。而演算法執行時間和執行程式碼行數成正比,大家一般習慣使用下邊公式表達,也就是大O複雜度表示法:

T(n)=O( f(n) )

  • n 表示資料的大小
  • T(n) 表示演算法執行的時間
  • f(n) 表示演算法執行程式碼的行數
  • O表示 T(n) 與 f(n) 存在正比關係

其實,大 O 時間複雜度實際上並不具體表示程式碼真正的執行時間,而是表示程式碼執行時間隨資料規模增長的變化趨勢,所以,也叫作漸進時間複雜度(asymptotic time complexity),簡稱時間複雜度。比如在演算法中n很大時,10萬、1億等,執行行數公式中的 常數、低階、係數三部分對“增長趨勢”的影響很小,甚至都可以忽略,而只需要記錄一個最大量級就可以了。

大O時間複雜度計算方法

如上所述,常數、低階、係數三部分對“增長趨勢”的影響可以忽略,而只保留最高項,所以計算方法如下(以含2階的

2ad7b0c7e341cab543d625ca3b9ffc0d.png

為例):

  1. 用常數 1 代公式中的常數項

151ba57ba68bfcc09a58b1dd71be23b5.png

=>

a79bc5ef7deb1f25d862064f7f3d35cb.png
  1. 只保留最高階項

a79bc5ef7deb1f25d862064f7f3d35cb.png

=>

92dd284ac9070527d945588d4b3067e0.png
  1. 去除最高階項的係數

92dd284ac9070527d945588d4b3067e0.png

=>

92dd284ac9070527d945588d4b3067e0.png

=>

56ab01b48595acbb4256f57465a8d77a.png

所以,用大 O 表示法表示示例1中演算法複雜度的話,演算法1:O(n),演算法2:O(1)。

往期精彩回顧

  1. 《90後程序員職場報告》:平均月薪近20K,每6個程式設計師就有1個是女性
  2. 手把手教你畫架構圖,看一次就會了
  3. 8種最坑的SQL錯誤用法,第一個就很坑?
  4. 一個公司有沒有未來,看它的老員工就知道了
  5. 【薦讀】你靠什麼在單位立足?​