關於算法複雜度

     通常我們衡量一段代碼的複雜度可以通過代碼的圈複雜度來衡量,而衡量一個程序流程處理算法的複雜度則可以通過算法的時間複雜度T(n)與空間複雜度(Space Complexity)衡量.

 

 

圈複雜度


      圈複雜度(Cyclomatic Complexity),該詞由Thomas J. McCabe, Sr 於1976提出,用來指示程序的複雜程度,它是一個軟件複雜度的度量標準.主要用來衡量代碼中所以線性獨立的路徑條數.圈複雜度大說明程序代碼可能質量低且難於測試和維護,根據經驗,程序的可能錯誤和高的圈複雜度有着很大關係.計算公式:

 

V(G)=e-n+2p  (e表示控制流圖中邊的數量,n表示控制流圖中節點的數量,p表示連通分支數)

 

其實,圈複雜度的計算還有更直觀的方法,因爲圈複雜度所反映的是“判定條件”的數量,所以圈複雜度實際上就是等於判定節點的數量再加上1,也即控制流圖的區域數,對應的計算公式爲:

 

V(G)=區域數-判定節點數+1

 

對於多分支的CASE結構或IF-ELSEIF-ELSE結構,統計判定節點的個數時需要特別注意一點,要求必須統計全部實際的判定節點數,也即每個ELSEIF語句,以及每個CASE語句,都應該算爲一個判定節點。

 

判定節點在模塊的控制流圖中很容易被識別出來,所以,針對程序的控制流圖計算圈複雜度V(G)時,最好還是採用第一個公式,也即V(G)=e-n+2p;而針對模塊的控制流圖時,可以直接統計判定節點數,這樣更爲簡單.

 

 更多詳細信息參考:

http://en.wikipedia.org/wiki/Cyclomatic_complexity

 

時間複雜度

 

時間複雜度(Time Complexity).在一個算法中,執行簡單操作的次數越少,則運行時間也越少.所以約定把算法中包含簡單操作的次數的多少叫做時間複雜度.


1.時間頻度

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

 

2.計算方法

  1. 一般情況下,算法的基本操作重複執行的次數是模塊n的某一個函數f(n),因此,算法的時間複雜度記做:T(n)=O(f(n))

  分析:隨着模塊n的增大,算法執行的時間的增長率和f(n)的增長率成正比,所以f(n)越小,算法的時間複雜度越低,算法的效率越高。

  2. 在計算時間複雜度的時候,先找出算法的基本操作,然後根據相應的各語句確定它的執行次數,再找出T(n)的同數量級(它的同數量級有以下:1,Log2n ,n ,nLog2n ,n的平方,n的三次方,2的n次方,n!),找出後,f(n)=該數量級,若T(n)/f(n)求極限可得到一常數c,則時間複雜度T(n)=O(f(n))

  例:算法:

  for(i=1;i<=n;++i)

  {

  for(j=1;j<=n;++j)

  {

  c[ i ][ j ]=0; //該步驟屬於基本操作 執行次數:n的平方 次

  for(k=1;k<=n;++k)

  c[ i ][ j ]+=a[ i ][ k ]*b[ k ][ j ]; //該步驟屬於基本操作 執行次數:n的三次方 次

  }

  }

  則有 T(n)= n的平方+n的三次方,根據上面括號裏的同數量級,我們可以確定 n的三次方 爲T(n)的同數量級

  則有f(n)= n的三次方,然後根據T(n)/f(n)求極限可得到常數c

  則該算法的 時間複雜度:T(n)=O(n的三次方)

3.分類

  按數量級遞增排列,常見的時間複雜度有:

  常數階O(1),對數階O(log2n),線性階O(n),

  線性對數階O(nlog2n),平方階O(n2),立方階O(n3),...,

  k次方階O(nk), 指數階O(2n) 。隨着問題規模n的不斷增大,

 

 

空間複雜度

空間複雜度(Space Complexity)是對一個算法在運行過程中臨時佔用存儲空間大小的量度。

  比如插入排序的時間複雜度是O(n^2),空間複雜度是O(1)

  而一般的遞歸算法就要有O(n)的空間複雜度了,因爲每次遞歸都要存儲返回信息

  一個算法的優劣主要從算法的執行時間和所需要佔用的存儲空間兩個方面衡量。

  類似於時間複雜度的討論,一個算法的空間複雜度(SpaceComplexity)S(n)定義爲該算法所耗費的存儲空間,它也是問題規模n的函數。漸近空間複雜度也常常簡稱爲空間複雜度。空間複雜度(SpaceComplexity)是對一個算法在運行過程中臨時佔用存儲空間大小的量度。一個算法在計算機存儲器上所佔用的存儲空間,包括存儲算法本身所佔用的存儲空間,算法的輸入輸出數據所佔用的存儲空間和算法在運行過程中臨時佔用的存儲空間這三個方面。算法的輸入輸出數據所佔用的存儲空間是由要解決的問題決定的,是通過參數表由調用函數傳遞而來的,它不隨本算法的不同而改變。存儲算法本身所佔用的存儲空間與算法書寫的長短成正比,要壓縮這方面的存儲空間,就必須編寫出較短的算法。算法在運行過程中臨時佔用的存儲空間隨算法的不同而異,有的算法只需要佔用少量的臨時工作單元,而且不隨問題規模的大小而改變,我們稱這種算法是“就地/"進行的,是節省存儲的算法,如這一節介紹過的幾個算法都是如此;有的算法需要佔用的臨時工作單元數與解決問題的規模n有關,它隨着n的增大而增大,當n較大時,將佔用較多的存儲單元,例如將在第九章介紹的快速排序和歸併排序算法就屬於這種情況。

  分析一個算法所佔用的存儲空間要從各方面綜合考慮。如對於遞歸算法來說,一般都比較簡短,算法本身所佔用的存儲空間較少,但運行時需要一個附加堆棧,從而佔用較多的臨時工作單元;若寫成非遞歸算法,一般可能比較長,算法本身佔用的存儲空間較多,但運行時將可能需要較少的存儲單元。

  一個算法的空間複雜度只考慮在運行過程中爲局部變量分配的存儲空間的大小,它包括爲參數表中形參變量分配的存儲空間和爲在函數體中定義的局部變量分配的存儲空間兩個部分。若一個算法爲遞歸算法,其空間複雜度爲遞歸所使用的堆棧空間的大小,它等於一次調用所分配的臨時存儲空間的大小乘以被調用的次數(即爲遞歸調用的次數加1,這個1表不開始進行的一次非遞歸調用)。算法的空間複雜度一般也以數量級的形式給出。如當一個算法的空間複雜度爲一個常量,即不隨被處理數據量n的大小而改變時,可表示爲O(1);當一個算法的空間複雜度與以2爲底的n的對數成正比時,可表示爲O(log2n);當一個算法的空I司複雜度與n成線性比例關係時,可表示爲O(n).若形參爲數組,則只需要爲它分配一個存儲由實參傳送來的一個地址指針的空間,即一個機器字長空間;若形參爲引用方式,則也只需要爲其分配存儲一個地址的空間,用它來存儲對應實參變量的地址,以便由系統自動引用實參變量。

  對於一個算法,其時間複雜度和空間複雜度往往是相互影響的。當追求一個較好的時間複雜度時,可能會使空間複雜度的性能變差,即可能導致佔用較多的存儲空間;反之,當=i自求一個較好的空間複雜度時,可能會使時間複雜度的性能變差,即可能導致佔用較長的運行時間。另外,算法的所有性能之間都存在着或多或少的相互影響。因此,當設計一個算法(特別是大型算法)時,要綜合考慮算法的各項性能,算法的使用頻率,算法處理的數據量的大小,算法描述語言的特性,算法運行的機器系統環境等各方面因素,才能夠設計出比較好的算法。算法的時間複雜度和空間複雜度合稱爲算法的複雜度。

 

 

參考文獻:

[1] .百度百科-圈複雜度: http://baike.baidu.com/view/3553594.htm

[2] .Wikipedia: http://en.wikipedia.org/wiki/Cyclomatic_complexity

[3] .百度百科-時間複雜度: http://baike.baidu.com/view/104946.htm

[4] .百度百科-空間複雜度: http://baike.baidu.com/view/540497.htm


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章