天天看點

5 分鐘了解下【圈複雜度】是如何計算的?

這是我參與11月更文挑戰的第2天,活動詳情檢視:[2021最後一次更文挑戰]

如圖是一張簡單的程式流程控制圖:

5 分鐘了解下【圈複雜度】是如何計算的?

程式由紅色的節點開始運作,然後進入循環(紅色節點下由三個節點組成),離開循環後有條件分支,最後運作藍色節點後結束;

由此流程控制圖,我們便可以開始計算該程式的 圈複雜度;

計算公式:​

​M = E − N + 2*P​

E 為圖中邊的個數,N 為圖中節點的個數,P 為圖中連通分量的個數。

此圖中,E = 9, N = 8, P = 1,因該程式圈複雜度為 9 - 8 + (2*1) = 3 ;

邊的個數和節點的個數很好了解,但:

什麼是 連通分量?

  • 原來,在無向圖中,如果任意兩個頂點之間都能夠連通,則稱此無向圖為連通圖;
5 分鐘了解下【圈複雜度】是如何計算的?

雖然 V1 和 V3 沒有直接關聯,但從 V1 到 V3 存在兩條路徑,分别是 V1-V2-V3 和 V1-V4-V3,是以稱 V1 和 V3 之間是連通的。

  • 若無向圖不是連通圖,但圖中存儲某個子圖符合連通圖的性質,則稱該子圖為 連通分量;如圖示:
5 分鐘了解下【圈複雜度】是如何計算的?
  • 而在有向圖中,若任意兩個頂點 Vi 和 Vj,滿足從 Vi 到 Vj 以及從 Vj 到 Vi 都連通,也就是都含有至少一條通路,則稱此有向圖為 強連通圖;
  • 若有向圖本身不是強連通圖,但其包含的最大連通子圖具有強連通圖的性質,則稱該子圖為 強連通分量。
5 分鐘了解下【圈複雜度】是如何計算的?

注意:圈複雜度計算中,計算變量是連通分量,而不是強連通分量!

判定法

上面通過公式來計算圈複雜度,似乎有點太過麻煩,計算邊、節點、連通分量,都要費不少勁!

有沒有更加粗暴簡單的方法呢?答案就是:判定法!

當程式遇到這些判定條件時,圈複雜度在原有基礎上加 1 即可;

  • if 語句
  • while 語句
  • for 語句
  • case 語句
  • catch 語句
  • and 和 or 布爾操作
  • ? : 三元運算符

接着以上節程式控制圖為例,正常順序的圈複雜度為 1,遇到 for 循環 +1,然後遇到 if 語句,再 +1 ,最後結果為 3;

怎樣,是不是夠粗暴簡單?判定法用于簡單程式的圈複雜度計算還是很有效果的;

需要注意的是:對于多分支的 case 結構或多個 if - else 結構,必須統計全部實際的判定條件數;

圈複雜度是評判代碼優劣的标準之一,通常來說,圈複雜度不要大于 5 ,否則代碼将會被判定為 不易讀!

降低圈複雜度大緻有如下方法:

  • 簡化、合并條件表達式
  • 将條件判定提煉出獨立函數
  • 将大函數拆成小函數
  • 以明确函數取代參數
  • 替換算法

從先計算後降低圈複雜度的角度來優化代碼,使代碼更加易讀、易擴充、易維護,這就叫【專業】!

我是掘金安東尼,公衆号同名,輸出暴露輸入,技術洞見生活,下次再會~