基本概念

圈复杂度(Cyclomatic complexity,简写CC)也称为条件复杂度,是一种代码复杂度的衡量标准。由托马斯·J·麦凯布(Thomas J. McCabe, Sr.)于1976年提出,用来表示程序的复杂度,其符号为VG或是M。它可以用来衡量一个模块判定结构的复杂程度,数量上表现为独立现行路径条数,也可理解为覆盖所有的可能情况最少使用的测试用例数。圈复杂度大说明程序代码的判断逻辑复杂,可能质量低且难于测试和 维护。程序的可能错误和高的圈复杂度有着很大关系。

计算方法

1. 点边计算法

对于一个控制流图的圈复杂度,其计算公式为:深度学习如何刻画模型的计算复杂度 模型圈复杂度_圈复杂度

其中,深度学习如何刻画模型的计算复杂度 模型圈复杂度_代码规范_02为控制流图中边的数量,深度学习如何刻画模型的计算复杂度 模型圈复杂度_代码规范_03为节点数量。

举几个栗子:

顺序结构的圈复杂度为(无论多长的顺序结构):1

while循环圈复杂度(增加一个while循环圈复杂度+1):2

if-else圈复杂度(增加一个if分支圈复杂度+1):2

Until同while

深度学习如何刻画模型的计算复杂度 模型圈复杂度_深度学习如何刻画模型的计算复杂度_04

2. 节点判别法

通过上述的点边计算法,可以发现,增加while分支或是if分支,圈复杂度就会+1,所以不难发现,每增加一个判定节点,圈复杂度就会+1,计算公式如下:

深度学习如何刻画模型的计算复杂度 模型圈复杂度_深度学习如何刻画模型的计算复杂度_05

其中深度学习如何刻画模型的计算复杂度 模型圈复杂度_圈复杂度_06为判定节点数,主要有如下类型:

  • if语句
  • while语句
  • for语句
  • case语句
  • catch语句
  • and和or布尔操作(判定语句中)
  • ?: 三元操作符

值得注意的是,对于多分支的case结构和if-elseif-else等结构,需要判断时间判定节点数,画个图就清楚了😊

计算栗子

栗子1

void sort(int * A)
{
int i=0;
int n=4;
int j = 0;
while(i < n-1)
{
    j = i +1
    while(j < n)
    {
        if (A[i] < A[j])
             swap(A[i], A[j]);
    }
    i = i + 1
}
}

所以圈复杂度为:深度学习如何刻画模型的计算复杂度 模型圈复杂度_代码规范_07

当然也可以使用点边计算法计算

栗子2

U32 find (string match){
         for(auto var : list)
         {
             if(var == match && from != INVALID_U32) return INVALID_U32;
         }
         //match step1
         if(session == getName() && key == getKey())
         {
             for (auto& kv : Map)
             {
                 if (kv.second == last && match == kv.first)
                 {
                     return last;
                 }
             }

         }
         //match step2
         auto var = Map.find(match);
         if(var != Map.end()&& (from != var->second)) return var->second;

         //match step3
         for(auto var: Map)
         {
             if((var.first, match) && from != var.second)
             {
                 return var.second;
             }
         }
         return INVALID_U32;
};

圈复杂度:深度学习如何刻画模型的计算复杂度 模型圈复杂度_深度学习如何刻画模型的计算复杂度_08

意义

一般来说圈复杂度大于10的方法存在很大的出错风险。圈复杂度和缺陷个数有高度的正相关:圈复杂度最高的模块和方法,其缺陷个数也可能最多。

圈复杂度

代码状况

可测性

维护成本

1-10

清晰、结构化



10-20

复杂



20-30

非常复杂



>30

不可读

不可测

非常高

所以在平时的代码编写过程中要注意降低代码的圈复杂度,可以采用拆分函数和优化表达等方式降低圈复杂度😘