1. 程式人生 > >圈複雜度計算例項

圈複雜度計算例項

個人學習筆記, 網上摘抄.

計算公式1:V(G)=e-n+2p。其中,

e表示控制流圖中邊的數量,

n表示控制流圖中節點的數量,

p圖的連線元件數目(圖的元件數是相連節點的最大集合)。因為控制流圖都是連通的,所以p為1.

 

計算公式2:

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

其實,圈複雜度的計算還有更直觀的方法,

因為圈複雜度所反映的是“判定條件”的數量,

所以圈複雜度實際上就是等於判定節點的數量再加上1,也即控制流圖的區域數。

 

對於多分支的CASE結構或IF-ELSEIF-ELSE結構,

統計判定節點的個數時需要特別注意一點,要求必須統計全部實際的判定節點數,也即每個ELSEIF語句,

以及每個CASE語句,都應該算為一個判定節點。

 

計算公式3:V(G)=R。其中R代表平面被控制流圖劃分成的區域數。

針對程式的控制流圖計算圈複雜度V(G)時,最好還是採用第一個公式,也即V(G)=e-n+2;

而針對模組的控制流圖時,可以直接統計判定節點數,

這樣更為簡單;針對複雜的控制流圖是,使用區域計算公式V(G)=R更為簡單。

 

圈複雜度(Cyclomatic Complexity)是一種程式碼複雜度的衡量標準。

它可以用來衡量一個模組判定結構的複雜程度,數量上表現為獨立現行路徑條數,

也可理解為覆蓋所有的可能情況最少使用的測試用例數。

圈複雜度大說明程式程式碼的判斷邏輯複雜,可能質量低且難於測試和維護。

程式的可能錯誤和高的圈複雜度有著很大關係。

各判斷語句的控制流圖

 

在計算圈複雜度時,可以通過程式控制流圖方便的計算出來。

通常使用的計算公式是V(G) = e – n + 2 , 

e 代表在控制流圖中的邊的數量(對應程式碼中順序結構的部分),

n 代表在控制流圖中的節點數量,包括起點和終點(1、所有終點只計算一次,即便有多個return或者throw;2、節點對應程式碼中的分支語句)。

 

//程式原始碼,圈複雜度為 2

public String case1(int num) {

       String string = null;

       if (num == 1) {

           string = "String";

       }

       return string.substring(0);

    }

 //上面程式碼的單元測試程式碼

    public void testCase1(){

       String test1 = case1(1);

    }

 

 

知道了如何計算圈複雜度,我們來使用控制流圖重新計算一次case1方法的圈複雜度,其控制流圖如下圖。狀態1表示if(num == 1 )的條件判斷,狀態2表示string=”String”的賦值操作。可以通過下面的控制流圖得到 e = 3 ; n = 3;那麼全複雜度V(G) = 3 - 3 + 2 = 2,既case1的圈複雜度為2。

 

圈複雜度主要與分支語句(if、else、,switch 等)的個數成正相關。

可以在圖1中看到常用到的幾種語句的控制流圖(表示程式執行流程的有向圖)。

當一段程式碼中含有較多的分支語句,其邏輯複雜程度就會增加。

 

===========================================================================

  public String case2(int index, String string) {

       String returnString = null;

       if (index < 0) {

           throw new IndexOutOfBoundsException("exception <0 ");

       }

       if (index == 1) {

           if (string.length() < 2) {

              return string;

           }

           returnString = "returnString1";

       } else if (index == 2) {

           if (string.length() < 5) {

              return string;

           }

           returnString = "returnString2";

       } else {

           throw new IndexOutOfBoundsException("exception >2 ");

       }

       return returnString;

    }

 

 

根據公式 V(G) = e – n + 2 = 12 – 8 + 2 = 6 。

case2的圈複雜段為6。

說明一下為什麼n = 8,雖然圖上的真正節點有12個,

但是其中有5個節點為throw、return,這樣的節點為end節點,只能記做一個。

 

在開發中常用的檢測圈複雜度的工具,PMD,checkstyle都可以檢測到高複雜度的程式碼塊。

在程式碼的開發中,配合各種圈複雜度的檢測外掛,將高複雜度的程式碼進行適當的拆分、優化,可以大大提高程式碼整體的質量,減少潛在bug存在。