一、控制流图绘制
1、控制流分析方法
-
通过生成程序的有效控制流图,来对代码进行分析。
2、控制流图图例
![](https://i-blog.csdnimg.cn/blog_migrate/391d58a3b350357d99ce21e06fbbace4.png)
(1)圆圈(结点)
-
表示一个语句;
-
一般对应无分支的一个或一组语句。可以理解为一个语句或一组按顺序执行的语句。
(2)箭头(边)
-
表示控制流的方向;
-
当控制流留到一个地方的时候需要做出决策(符合什么条件走哪一个方向),例如if...else...控制流图。
二、常规结构的控制流图绘制
1、“顺序结构”控制流图
![](https://i-blog.csdnimg.cn/blog_migrate/fb0206423601a2deaea44c3b3afbf3c6.png)
-
执行完语句1后执行语句2,执行完语句2后执行语句3。
-
像这种顺序结构对程序的复杂性不产生影响,所以绘制顺序结构的控制流图时可以简单的绘制成一个圈。
2、“分支结构”控制流图
(1)“两分支结构”控制流图
![](https://i-blog.csdnimg.cn/blog_migrate/85bc9523ce83acfbf85e345b28eaf258.png)
-
else print("Failed\n");:是一个顺序结构,所以一般在控制流图中直接将这两个语句简化成一个圆圈了。
-
汇聚结点:当一段程序代码在执行的过程中没有共同执行的部分,就需要在程序的控制流图后加一个汇聚结点(一个空圈圈)。例如程序控制流在分叉之后直接结束了,没有这两个分叉共同执行的后续代码,就需要加一个空圈圈作为汇聚结点( 分叉之后没有闭合就需要加一个汇聚结点);当控制流分叉之后还有分叉(if...else...语句后还有并行的if...else...语句),控制流图中不需要汇聚结点,直接将上一个分叉的控制流连到下一个分叉的控制流即可。
(2)“?结构”控制流图
![](https://i-blog.csdnimg.cn/blog_migrate/551f461ed95260842a81320f1a346b08.png)
(3)“多分支结构”控制流图
![](https://i-blog.csdnimg.cn/blog_migrate/28f74193cd6f0e1c5265a6106959b5df.png)
![](https://i-blog.csdnimg.cn/blog_migrate/edf2eee660ad84c45fe216cb098dfbd5.png)
-
Switch(变量):Switch后的括号中是变量,变量的比较是在case语句中进行的,Switch和case组合在一起才是一个判定,所以绘制控制流图的时候需注意,要将Switch和case绘制到一个结点(一个圆圈),而不是两个圆圈。
-
default:缺省值,如果grade的值不符合case的任意一种情况,则走缺省。
例如上图中执行完
case'A'之后会接着执行case'a',然后才会执行到break,所以最终画出的控制流图如图1所示,与case多分支标准控制流图有出入,需注意;
但如果case'A'后有break语句,那么控制流图如图2所示,与标准case多分支结构的控制流图是一样的。
- Break:在Switch case结构中,如果没有break语句执行中断去打破这个结构,那么在执行完上面的case语句后会紧接着执行下面的case语句,直到遇到break后中断。
3、“循环结构”控制流图
(1)"for循环结构"、“until循环结构”、“while循环结构”控制流图
![](https://i-blog.csdnimg.cn/blog_migrate/84bf54fb574900cd5743c14ac6382dd9.png)
-
这三个循环的控制流图基本是一样的
-
while和for循环:都是先判断循环条件,当循环条件为真时执行循环体的内容,执行完循环体的内容后再返回判断点,再次判断是否满足循环条件;当不满足循环条件时则跳出循环执行循环后面的语句结构。
-
until循环:先判断循环条件,当循环条件为假时执行循环体的内容,执行完循环体的内容后返回判断点,再次判断循环条件,当循环条件为真时,跳出循环执行循环后面的语句结构。
“while循环”控制流图
![](https://i-blog.csdnimg.cn/blog_migrate/e47108717827332dd283b701c396b624.png)
-
{}在什么情况下使用:当结构体后面要执行的语句大于等于2条时,必须使用花括号;循环条件后要执行的语句只有一条时,花括号可以省略。
“for循环”控制流图
![](https://i-blog.csdnimg.cn/blog_migrate/8f84d3368e6fe368e81c669372e84760.png)
(2)"do...until循环"、“do...while循环”控制流图
-
先执行循环体后判断循环条件
![](https://i-blog.csdnimg.cn/blog_migrate/4c6868d022cd1f18b19f6840e557bc62.png)
三、绘制控制流图注意项
![](https://i-blog.csdnimg.cn/blog_migrate/4d2b0634db3a6c6c20d99f7d48e42f76.png)
1、圆圈
-
考试时以“//数字”的形式表示的语句就是需要绘制到控制流图中的语句,将数字写到控制流图的圆圈内。
2、箭头(边)
-
表示控制流的方向
3、区域
-
结点(圆圈)和箭头(边)围成的封闭的空间就是一个区域
4、控制流程图绘制
-
一组顺序结构:可以简化为一个圈
-
汇聚结点:分叉之后没有闭合就需要加一个空圆圈表示汇聚结点
-
复合条件表达式:要拆成嵌套的单条件结构。与是在为真的条件中嵌套第二个条件,或是在为假的条件中嵌套第二个条件,如下图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/fdcba488fe1686ebe6e75b65ef0bd37c.png)
四、控制流图绘制案例
![](https://i-blog.csdnimg.cn/blog_migrate/c1a05eb0ff46435564fc5029eb1f2a45.png)
-
return:不论return语句在函数的哪个位置,只要执行return语句,就会直接到函数的最后。
![](https://i-blog.csdnimg.cn/blog_migrate/7db7e0bc858d3e8ea1c5578df7d456f1.png)
五、McCabe圈复杂度
推荐使用第三种
-
V(g)=边的数量-结点数量+2
-
V(g)=判断节点数+1
-
V(g)=封闭区域数+1
![](https://i-blog.csdnimg.cn/blog_migrate/2fa03c25a27ca23943a636a6cd23a12b.png)
六、圈度复杂性建议
-
算出圈度复杂度之后,这个值告诉我们采用独立路径覆盖方法时,独立路径最大的数量是几条。
七、独立路径
-
一条路径中至少有一段路径在之前的路径中没有包含过的就是独立路径。
-
独立路径的条数=V(g)
![](https://i-blog.csdnimg.cn/blog_migrate/c3f451db1c5a7c2ccff0e5e401367126.png)
八、函数调用关系图
1、扇入
-
对于当前模块来讲,他被调用的次数叫做扇入;
-
一个模块的扇入越大,就说明当前模块在系统中被重复利用的次数就越多,说明当前模块的通用性就越强。
2、扇出
-
一个模块要完成其功能,需要调用其他模块的数量;
-
一个模块的扇出数越大,说明当前模块越复杂,一般不建议扇出数大于7。
3、扇入扇出应用
九、考点
1、利用V(g)的计算公式计算V(g)值
![](https://i-blog.csdnimg.cn/blog_migrate/7ddcf1422d902b97c4f5995df4d69f87.png)
![](https://i-blog.csdnimg.cn/blog_migrate/90de4b087e574860c08c69d164375e52.png)