函数圈复杂度(Cyclomatic Complexity),也称为圈复杂度或麦凯布复杂度,是衡量代码复杂度的一种指标。它由计算一个函数或模块中独立执行路径的数量得出,反映了程序的控制流复杂性。
圈复杂度的核心思想是,函数的复杂性越高,代码中的分支、循环和条件判断越多,程序的独立路径数就越多。因此,圈复杂度越高,代码可能越难以理解、测试和维护。
计算方法
函数圈复杂度的基本计算公式是:
M = E - N + 2P
- M:圈复杂度(Cyclomatic Complexity)。
- E:控制流图中的边数(Edges),即程序中的控制转移路径(例如从一个语句到另一个语句)。
- N:控制流图中的节点数(Nodes),即程序中的代码块(例如一个条件判断、循环、或者简单的赋值语句)。
- P:程序中的连通分量数(Connected components),对于大多数函数来说,P = 1。
在大多数情况下,可以使用一个更简单的方法来估算圈复杂度:计算函数中的控制结构。每遇到一个控制结构,如if
、else if
、for
、while
、switch case
等,圈复杂度就增加1。
圈复杂度的简单规则
- 没有分支的直线代码:圈复杂度为1。
- 每个
if
语句或else if
分支:圈复杂度增加1。 - 每个
for
或while
循环:圈复杂度增加1。 - 每个
switch
语句的case
子句:每个case
增加1。 - 每个
catch
语句:增加1。
示例代码和圈复杂度计算
示例 1:简单函数
int add(int a, int b) {
return a + b;
}
这个函数没有任何条件分支或循环,圈复杂度为 1。
示例 2:带有if-else
语句的函数
int max(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
- 这里有一个
if-else
结构,圈复杂度为 2,因为有两个独立路径。
示例 3:带有if-else
和循环的函数
int findMax(const std::vector<int>& nums) {
int max = nums[0];
for (int i = 1; i < nums.size(); ++i) {
if (nums[i] > max) {
max = nums[i];
}
}
return max;
}
- 这里有一个
for
循环和一个if
条件判断:for
循环:圈复杂度增加1。if
语句:圈复杂度增加1。- 初始复杂度为1(没有控制结构的情况下)。
- 圈复杂度总计为 3。
圈复杂度的重要性
圈复杂度越高,函数的复杂性越高,可能带来以下问题:
- 可读性下降:复杂的控制流结构使得代码更难理解和维护。
- 测试难度增加:需要更多的测试用例来覆盖所有的独立执行路径,确保代码的正确性。
- 错误风险增加:复杂的代码往往更容易引入错误,尤其是在修改和扩展时。
圈复杂度的最佳实践
- 圈复杂度不应过高,一般来说一个函数的圈复杂度应尽量保持在10以下。对于复杂度超过10的函数,应该考虑重构代码,划分为多个更简单的函数。
- 单一职责原则:一个函数只应该做一件事,遵循这一原则可以有效降低圈复杂度。
- 早期返回(early return):通过减少嵌套层级来降低复杂度。
- 重构:如果发现函数复杂度过高,可以尝试将代码中的不同逻辑分解为多个小函数。
总结
函数圈复杂度是衡量代码复杂性的重要指标,它与代码中的分支和循环直接相关。圈复杂度越高,代码越难测试、理解和维护。合理控制代码的圈复杂度是写出可维护、高质量代码的关键之一。
标签:语句,函数,int,代码,else,复杂度 From: https://www.cnblogs.com/chentiao/p/18468739