這是我參與11月更文挑戰的第2天,活動詳情檢視:[2021最後一次更文挑戰]
如圖是一張簡單的程式流程控制圖:
程式由紅色的節點開始運作,然後進入循環(紅色節點下由三個節點組成),離開循環後有條件分支,最後運作藍色節點後結束;
由此流程控制圖,我們便可以開始計算該程式的 圈複雜度;
計算公式:
M = E − N + 2*P
E 為圖中邊的個數,N 為圖中節點的個數,P 為圖中連通分量的個數。
此圖中,E = 9, N = 8, P = 1,因該程式圈複雜度為 9 - 8 + (2*1) = 3 ;
邊的個數和節點的個數很好了解,但:
什麼是 連通分量?
-
- 原來,在無向圖中,如果任意兩個頂點之間都能夠連通,則稱此無向圖為連通圖;
雖然 V1 和 V3 沒有直接關聯,但從 V1 到 V3 存在兩條路徑,分别是 V1-V2-V3 和 V1-V4-V3,是以稱 V1 和 V3 之間是連通的。
-
- 若無向圖不是連通圖,但圖中存儲某個子圖符合連通圖的性質,則稱該子圖為 連通分量;如圖示:
-
- 而在有向圖中,若任意兩個頂點 Vi 和 Vj,滿足從 Vi 到 Vj 以及從 Vj 到 Vi 都連通,也就是都含有至少一條通路,則稱此有向圖為 強連通圖;
- 若有向圖本身不是強連通圖,但其包含的最大連通子圖具有強連通圖的性質,則稱該子圖為 強連通分量。
注意:圈複雜度計算中,計算變量是連通分量,而不是強連通分量!
判定法
上面通過公式來計算圈複雜度,似乎有點太過麻煩,計算邊、節點、連通分量,都要費不少勁!
有沒有更加粗暴簡單的方法呢?答案就是:判定法!
當程式遇到這些判定條件時,圈複雜度在原有基礎上加 1 即可;
-
- if 語句
- while 語句
- for 語句
- case 語句
- catch 語句
- and 和 or 布爾操作
- ? : 三元運算符
接着以上節程式控制圖為例,正常順序的圈複雜度為 1,遇到 for 循環 +1,然後遇到 if 語句,再 +1 ,最後結果為 3;
怎樣,是不是夠粗暴簡單?判定法用于簡單程式的圈複雜度計算還是很有效果的;
需要注意的是:對于多分支的 case 結構或多個 if - else 結構,必須統計全部實際的判定條件數;
圈複雜度是評判代碼優劣的标準之一,通常來說,圈複雜度不要大于 5 ,否則代碼将會被判定為 不易讀!
降低圈複雜度大緻有如下方法:
-
- 簡化、合并條件表達式
- 将條件判定提煉出獨立函數
- 将大函數拆成小函數
- 以明确函數取代參數
- 替換算法
從先計算後降低圈複雜度的角度來優化代碼,使代碼更加易讀、易擴充、易維護,這就叫【專業】!
我是掘金安東尼,公衆号同名,輸出暴露輸入,技術洞見生活,下次再會~