本节书摘来自华章社区《C语言程序设计:问题与求解方法》一书中的第3章,第3.4节验证算法的方法,作者:何 勤,更多章节内容可以访问云栖社区“华章社区”公众号查看
3.4 验证算法的方法
前面说过,找到求解问题的算法对解决编程问题至关重要。但如何验证算法的正确性呢?本节将介绍采用画变量(内存单元)取值变化图来验证算法的方法(参见对例题3.3的算法验证),这也是成为程序员或编程高手的一种极为重要的技能。采用这种方法有两个好处:
1)大大减少不必要的编程工作量。在写出算法而尚未编出程序时,就可以检查算法是否存在逻辑错误或边界错误(数组的边界错误,或者循环次数多一次或少一次)、程序的流程是否构造正确等,从而减少了不必要的编程工作量。这类似于在装修前画出立体效果图,让用户感受一下在其中生活是否会感到舒服一样。如果用户感觉不好,可重新修改设计,大大减少了实际装修完后才返工的极大损失。毕竟重写和修改伪代码要比重写或修改程序省事多了—尤其是对一个大型程序。
2)可使读者读懂较难程序或算法的能力得到极大的提高。而阅读程序和算法的能力,是一个人能够否成为编程高手的最重要的、决定性因素之一。
希望读者至少用这种方法来分析和阅读几十个你认为比较难懂而又比较有趣的算法或程序,使之成为你的编程工具箱中的一件“利器”,并且养成一种良好的编程习惯。在用伪代码写出算法后,不要急于把它转换成高级语言的程序,而是用这种在纸面上运行、走查的方法去验证算法,尽可能在早期找出并修改算法中的逻辑错误或边界错误。
当然,即使通过这种验证,也不能保证这个算法是完全正确和完善的。对于语法错误更是无能为力。但这种验证的重要价值,我们绝对不能否认。
如果不用此方法来进行验证,在写出算法后就立即编程。仅仅依赖于运行编译程序来进行简单调试,你很可能最终会得到一个没有任何语法错误和运行时错误的程序。然而,此程序得到的结果要么可能是完全不正确的(逻辑错),要么此程序存在边界错误。如果是逻辑错误,则整个编程和调试工作完全是白费力气。在编写大型程序时,这种时间的浪费是一个很严重的问题。
【例题3.3】将一个三位整数反向后输出。(类型:必修题;趣味性:;难度:*)
一级算法:
1 输入一个三位整数→n
2 通过利用学过的算术运算符整除 / 和取余数 % 进行分解,分别求出此三位整数n的百位数n3,十位数n2和个位数n1
3 反向后的三位整数为 num=n1100+n210+n3
4 输出此三位数
其中第2步由于不能立即写出C语言的语句,需要进一步求精:
2.1 求出n的百位数:n3=n/100
2.2 求出n的十位数:n2=(n-n3*100)/10
2.3 求出n的个位数:n1=n%10
算法验证:执行算法第1步,假设将一个任意指定的三位整数(比如315)输入变量n中,用于验证上述算法过程的正确性。执行算法第1步后,变量的内存单元取值将如图3-1所示。
n3 n2 n1 num
315 不确定 不确定 不确定 不确定
执行算法2.2步的赋值语句n2=(n–n3100)/10。先计算表达式(n–n3100)/10,将n和n3的当前值从内存中取出代入表达式,进行表达式规定的运算:(315–3*100)/10,得到结果1 ,存入变量n2中。算法2.2步执行完后,变量的内存单元取值将如图3-3所示(变量n2的值发生了变化)。
n n3 n2 n1 num
315 3 1 不确定 不确定
经过以上验证,315确实变成了513,算法逻辑上的确是正确的。
将上述经过纸面运行走查验证的算法,转化为C语言程序如下:
1 #include<stdio.h>
2 int main(void)
3 {
4 int n;/*输入变量*/
5 int n3,n2,n1;/*中间变量*/
6 int num; /* 结果变量*/
7 /*输入一个三位整数n*/
8 printf("请输入一个三位整数\n");
9 scanf("%d", &n);
10
11 /*分别求出它的百位数n3,十位数n2,个位数n1*/
12 n3=n/100;
13 n2=(n-n3*100)/10;
14 n1=n%10;
15
16 /*反向后的三位整数为*/
17 num=n1*100+n2*10+n3;
18
19 /*输出此三位数*/
20 printf("num=%d",num);
21 return 0;
22 }
【问题1】是否可以将第17行和第20行合并为下面这一句并删掉第6行?
printf("num=%d", n1*100+n2*10+n3);
答:可以。printf()函数调用时,格式串后的输出项可以是一个表达式。
【问题2】是否可以将第12行和第13行颠倒语句次序?用画变量内存单元取值变化图的方法验证你的结论。
答:不可以。变量n3会出现初始化错误。第13行表达式中的n3依赖第12行的语句初始化。
【问题3】是否可以将第13行与第14行互换?
答:可以。因为两条赋值语句之间的变量并没有依赖关系。
【问题4】是否可以将所有变量n,n3,n2,n1都用float型来定义?
答:不可以。程序第12行、第13行的赋值语句的表达式,都要求是整除运算。第14行的n%10,运算符 % 也要求变量n是整型,而不是实型。