隨筆:估算程式演算法複雜度的理解

王滔發表於2014-04-10

大體分為:事前估算(設計演算法之前就估算此演算法效能)和事後估算(執行後,通過收集資料)

直覺上以為是事後估算為主,畢竟,實踐是檢驗真理的標準嘛。事後收集資料才是比較靠譜的。

 

不過,想法錯了。現在才明白,以"事前估算"為主要辦法。

為什麼事後估算的辦法不怎麼使用呢?

1、輸入的資料量沒法真實模擬。比如輸入的資料量是100,兩種演算法之間並不明顯差異。而輸入的資料量是100萬的時候,才會看到明顯的差異。但在我們的實驗環境下,很難做到這麼真實的測驗,缺乏這種環境。如果都放到事後去估算,因為沒法真實測驗,那就會很麻煩。

我的一個實際感受是,在資料庫測驗中,即便我們在實驗環境下,可以模擬輸入100萬行資料,我只有5個欄位的行。但在真實的應用環境下,100萬資料又比這複雜些。會有10個欄位的行。

2、受制於硬體環境。兩種演算法,a演算法比b演算法好。但b演算法是在效能優越的機器上測驗,所以沒看出比a演算法差在哪裡,結果是兩個演算法看不出明顯的差別。

最終,硬體好可以掩蓋比較劣質的演算法,劣的演算法看不出有多劣質。

 

那是不是說,讓兩種演算法在同樣的機器上來測驗就ok了呢?我也嘗試尋找對這個疑惑的解釋,留在這裡。有質疑才會有進步

 找到了解釋,即便在同樣的機器上來進行測試,但由於計算機的記憶體使用率、cpu使用率是動態變化的,使用情況不同,造成的測試結果也會不同。

 

 

事前估算主要跟資料輸入量、執行次數兩個因素有關。

 

 瞭解幾個術語與符號表示,因為業界都是這些術語與符號來描述,如果不清楚,就難以看懂他們的要表達的意思

T(n)

f(n)

 

有些解釋太文縐縐了,繞來繞去,我沒怎麼理解。

演算法的時間複雜度記做:T(n)=O(f(n));

 

我的理解:

 

T是英文單詞的time的簡寫,T(n)表示演算法要執行的時間耗費。

F應該是,Frequency Count的簡稱。理解為次數的意思。

每條語句的執行時間=語句的執行次數(即頻度(Frequency Count))×語句執行一次所需時間。

每條語句就是程式中的一句程式碼。比如一句程式碼習慣用分號";"來結束。這個我覺得不必糾結很細。可以是一個函式的呼叫,如果在for迴圈中,只算多少次迴圈就可以了。

 

計算一個演算法的複雜度分為兩個方面:時間複雜度和空間複雜度。

時間複雜度,就是執行這個演算法需要耗費多長時間,這是通俗解釋了。

空間複雜度,就是執行這個演算法需要多少記憶體空間(因為最終計算都是在記憶體中進行,不是在磁碟中)

先不需要了解如何計算一個演算法耗費多少記憶體,看看需要執行多長時間,怎麼計算

 

下面解釋了緣由:

一個演算法執行所耗費的時間,從理論上是不能算出來的,必須上機執行測試才能知道。但我們不可能也沒有必要對每個演算法都上機測試,只需知道哪個演算法花費的時間多,哪個演算法花費的時間少就可以了。並且一個演算法花費的時間與演算法中語句的執行次數成正比例,哪個演算法中語句執行次數多,它花費時間就多。一個演算法中的語句執行次數稱為語句頻度或時間頻度。

 

 

我喜歡上面這麼通俗的解釋,意思是,測驗一個演算法是時間複雜度,可靠的辦法是對執行期間執行的操作次數進行統計,因為操作次數越多,耗費的時間肯定越多

演算法的準確執行時間算不出來(因為在不同硬體、記憶體佔有情況下執行時間不同),只能通過執行次數來間接判斷(這樣拋開了硬體環境等影響)。執行次數越多的演算法肯定越不好

 

   於是:時間複雜度計算,變成了對執行次數進行統計。那怎麼統計執行次數,用什麼來表示呢?

   用f(n)來表示:輸入量為n的情況下,執行次數是多少。f(n)是一個函式。

 

    關於函式的漸近增長的理解:f(n)的漸近增長大於g(n),就是表示隨著n輸入值變大,f演算法的執行次數要大於g演算法,所以漸近增長值越大,演算法越不好。

 

    最終:根據"測驗時間複雜度最終是測驗執行次數"這個方式,我們只要測量f(n)的情況,就能側面測驗時間複雜度T(n)了。

 

   T(n)=0(f(n))           時間複雜度常用大O符號表述

  表示,演算法執行時間的增長率和f(n)的增長率相同。這裡面相同業界命了一個名稱,漸近時間複雜度,簡稱為時間複雜度。

  可以看出,這個時間複雜度,是一個近似的值,就像命名那樣子,漸近(的)時間複雜度。

 

 

  總結:事前估演算法,能夠做到拋開硬體、軟體因素影響演算法的測驗

 

 

 

 

相關文章