1、1,6.9 典型算法示例,1 递推法,递推法的编程思路是:,问题的共同特点是:前后项存在一定的关系,即后项可由前项推导出。,第一步:设项号,找前后项关系;1,可直接由前项推出后项2,可直接利用项号推出当前项的值3,需要综合利用项号和前项推出后项 第二步:构造重复结构; 第三步:设定变量初始值。,2,例6.5 编写求 1-2+3-4+5- . -100的和程序。第一步:设定项号,定义变量,找前后项关系 这是关键的一步。设定项号n =1 2 3 4 .sum=1-2+3-4+5- . 100存和 前后项关系为n=n+1,比较简单。生成的数n有正负号,且有规律:奇数为正,偶数为负,可用二选一if语句
2、判别;这里定义一个变量s判别。,第二步:构造重复结构求解这类题目,循环体总要执行多次。采用do while重复结构是很自然的。用其它重复结构,可行吗?,3,do n=n+1; s=-s;sum=sum+s*n; while (n100);,第三步:设置变量初值设置变量初值是保证正确计算出第一项值。十分明显,各变量的初值为:int n=0, sum=0, s=-1;,第四步: 静态检查跟踪三步左右,如果结果是正确的,一般情况下,可断定算法是正确的。,4,语句 第一次循环 第二次循环 第三次循环n=n+1; 1 2 3s=-s 1 -1 1sum=sum+s*n; 1 -1 2,第五步:编程通过上
3、述分析,确定了数据结构,定义了有关变量和类型(因明显是整型,未作说明),完成了算法设计。接下来编程就是用C语言精确表述这一思维过程。/* 求 1-2+3-4+5- . -100的和 chap6_5.c */ #include void main() int sum=0,n=0,s=-1; printf(“ * 运行结果 *n“);,5,do n+; s=-s; sum+=s*n; while (n100);printf(“1-2+3-4+ . -100=%dn“,sum); * 运行结果 *1-2+3-4+ . -100=-50,例6.6 编写下述功能程序:求 sinx=x-x3/3!+x5/
4、5!-x7/7!+ . 的近似值,误差为110-8。,6,do n+; s=-s; sum+=s*n; while (n100);printf(“1-2+3-4+ . -100=%dn“,sum); * 运行结果 *1-2+3-4+ . -100=-50,例6.6 编写下述功能程序:求 sinx=x-x3/3!+x5/5!-x7/7!+ . 的近似值,误差为110-8。,7,第一步:设定项号,定义变量,找前后项关系设定项号n=1 2 3 4 .sinx=x-x3/3!+x5/5!-x7/7!+ .存sin函数值 存x的幂xn 存阶乘fact 前后项关系比较复杂。从整体找前后项关系比较困难,分别
5、找前后项的分子和分母的关系比较简便。前后项关系:分子 xn = -xn*x*x 分母 fact=fact*(2*n-2)*(2*n-1),8,第二步: 构造重复结构求解这类题目,循环体总要执行多次(循环次数不确定),一般采用do while重复结构。 don=n+1; xn=-xn*x*x;fact=fact*(2*n-2)*(2*n-1);sinx=sinx+xn/fact; while (fabs(xn/fact)1e-8);,第三步:设置变量初值float x; double n=1, xn=x, fact=1, sinx=x;为保证精度,xn,fact,sinx取double型。为防止
6、溢出,n也取double。,9,第四步: 静态检查跟踪三步左右,如果结果正确,一般情况下,算法是正确的。语句 第一次循环 第二次循环 第三次循环n=n+1; 2 3 4xn=-xn*x*x; -x3 x3 -x7fact=fact*(2*n-2)*(2*n-1); 3! 5! 7!sinx=sinx+xn/fact; x-x3/3! x- x3/3!x5/5! x- x3/3!x5/5!-x7/7!,第五步:编程 /* 求 sinx=x-x3/3!+x5/5!-x7/7!+ . 的近似值 chap6_7.c */ #include #include #define EPS 1e-8 /* 符号
7、常量,误差 */,10,void main() float x; double n=1,xn,fact=1,sinx;,printf(“ * 运行结果 *n“);printf(“输入x:“);scanf(“%f“, /* 不在变量定义时置初值,为什么?*/,do n=n+1; xn=-xn*x*x; fact=fact*(2*n-2)*(2*n-1);sinx=sinx+xn/fact; while (fabs(xn/fact)EPS);,printf(“递推法 sin%0.4f=%0.8fn“,x,sinx);printf(“调库函数 sin%0.4f=%0.8fn“,x,sin(x); ,
8、* 运行结果 * 输入x:1 递推法 sin1.0000=0.84147098 调库函数 sin1.0000=0.84147098,11,例如: 求 a1/2 的近似值迭代公式: xn+1=(xn+a/xn)/2 误差公式:|xn+1- xn|=EPS,float a;,/*由用户输入*/,/*存当前近似值*/,/*暂存前一次的近似值*/,数据:,double x0;,double x1;,主要算法:,x1 =a/2; do x0=x1; /保存当前解x1=(x0+a/x0)/2; /计算新解 while( fabs(x1-x0)EPS );,2 迭代法,问题具有的共同特点是:已知迭代公式和误
9、差公式。可直接应用重复结构,按迭代公式计算一个新解,并与前一个解比较,直到满足误差要求为止。,scanf(“%f”,&a);,12,下面以例说明分析问题和算法设计的方法。例 6.7 编写求a1/2的近似值程序。迭代公式和误差公式是数学工作者研究的课题。编程是应用数学工作者研究的成果,快速求出满足精度要求的值。有了迭代公式和误差公式,求解这类问题十分简单。定义原根x0表示xn,新根x1表示xn+1,其类型取double。为什么不直接用xn和xn+1? 先以求21/2根为实例,按迭代法重复计算三次,观察根值的变化趋势。a为2, 定义一个新根x1=a/2,其初值为 1.0, 重复按迭代公式计算一个新
10、根:语句 第一次循环 第二次循环 第三次循环 x0=x1; 1.0 1.5 1.417 x1=(x0+a/x0)/2; 1.5 1.417 1.414,从上面x1的各次计算值可以看出:x1值一步一步逼近21/2的根值。求解这类问题,一般都采用do while重复结构实现。,13,x1=a/2; /* 选定初值 */do x0=x1; /* 前一次根值 */x1=(x0+a/x0)/2; /* 按迭代公式计算一个新根值 */ while (fabs(x1-x0)ESP); /* 判别是否满足误差要求 */选择x1初值为2是否可以?为什么不选x0初值为a/2?,依据上面分析,编写求a1/2近似值的
11、完善程序就不感到困难了。/* 应用迭代法求a1/2的近似值 chap6_8.c */ #include #include #include #define EPS 1e-8 void main() float a; double x0,x1;,14,printf(“ * 运行结果 *n“); printf(“读入一个实数:“);scanf(“%f“,x1=a/2; /* 选定初值 */do x0=x1; /* 前一次根值 */x1=(x0+a/x0)/2; /* 按迭代公式计算一个新根值 */ while (fabs(x1-x0)EPS);,printf(“迭代法 sqrt(%f)=%0.8f
12、n“,a,x1); printf(“调库函数 sqrt(%f)=%0.8fn“,a,sqrt(a);,15,* 运行结果 * 读入一个实数:123.987 迭代法 sqrt(123.987000)=11.13494497 调库函数 sqrt(123.987000)=11.13494497,16,3 枚举法,问题具有的共同特点是:不能用方程求解,只能一一列举各种情况,选取满足要求的解。可应用for嵌套结构实现。,例如:“百鸡问题”鸡翁一,值钱五,鸡母一,值钱三,鸡雏三,值钱一, 百钱买百鸡, 问鸡翁、鸡母、鸡雏各几何。,int i;/*鸡翁*/ int j;/*鸡母*/ int k;/*鸡雏*/
13、,数据:,主要算法:,for (i=1;i20;i+)for (j=1;j33;j+)k=100-i-j;if (15*i+9*j+k=300)printf(“%4d %7d %7dn“,i,j,k);,17,【补P129 6.7】编程序求210000以内的完全数。,完全数:一个数的因子(除了这个数本身)之和等于该数本身。,思路: 设定i从2变到10000,对每个i找到其因子和s; 判定 i=s?若相等,则i为完全数,否则不是。,例如:6的因子是1、2、3,因子和 1+2+36 因此 6 是完全数,使用穷举算法 用双层循环实现,18,算法和程序:,void main( ) int i,j,s;
14、for (i=2; i=10000; i+) s=0;for (j=1; ji; j+)if (i%j=0)s+=j;if (i=s)printf(“%6dn“,s); ,19,思路:素数是指只能被1和它本身整除的数,如5、7、11、17、等。,分别用2、3、,n-1尝试能否整除整数n。如果n能被某个数整除,则n就不是素数。,这是一种穷举算法 设除数为j,从2循环到n-1,20,算法和程序:,#include void main( ) int j,n;printf(“Enter an integer number: “);scanf(“%d“, ,21,程序的优化,对于穷举法来说,为了提高程序
15、的效率,就要减少尝试次数。,#include main( ) int j,m,k;printf(“Enter an integer number: “);scanf(“%d“, ,思考:如何输出100200中所有的素数,22,例题:从红、黄、兰、白、黑五种颜色的球中取出三种颜色的球,问共有几种取法。,分析:可以使用整型常量1,2,3,4,5分别表示红、黄、兰、白、黑五种颜色,就可以声明三个int型变量分别存放三次取球的颜色: int c1,c2,c3; /分别存放第1,2,3次取球的颜色,取值范围为:15 int count;/计数器,算法: count=0; for(c1=1;c1=5;c1
16、+)for(c2=1;c2=5;c2+)for(c3=1;c3=5;c3+)if(c3!=c1 ,if(c2=c1) continue;,&c1!=c2,23,【补】编程序,输出以下图形。,*,一共有4 行,每行由空格和星号组成:空格数按行增加,星号按行减少 变量 i 控制输出行数, 从1变化到4 变量 j 控制输出每行的空格和星号: j 从1变化到 i-1,每次输出一个空格 j 从1变化到 8-(2*i-1),每次输出一个星号,使用双重循环实现,思路:,4 其他,24,算法和程序:,void main( ) int i,j;for (i=1; i=4; i+) for (j=1; j=i-1
17、; j+)printf(“ “);for (j=1;j=8-(2*i-1);j+)printf(“*“);printf(“n“);,思考: 如何输出10行图形? 输出图形向右平移20个字符位置,应如何修改程序?,25,思路:,数制转换将二进制数、八进制数和十六进制数转换为十进制数。,【补】编写将十六进制数转换为十进制数程序。,求解这一问题的关键是如何将字符转换为整数的数字?,(1)将数字字符0 9转换为整型数的数字0 9,可用表达式ch-0描述。例如ch为0,则0-0=48-48,其值为0。(2)将大写字母A F转换为整型数的数字10 15,可用表达式ch-55描述。例如 ch为A,则A-55
18、=65-55,其值为10。而将小写字母都先转换为大写的,ch=ch-32; 再统一处理。,26,阅读程序 习题1,void main() int a=0,i;for(i=8;i=1;i-)switch(i) case 1: case 2: a+=1;break;case 3:case 4: a+=2;break;case 5: break;case 6: ;default: if(i%2) a+=3;printf(“a=%dn”,a); ,27,#include void main() int n=0;double facts=0,fact=1.0;do n+=1;fact*=n; facts+=fact;while(n20);printf(“写出facts值公式:”);printf(“n”); ,#include void main() int n=15469,k=2,i;for(i=1;ik;i+)n/=10;printf(“数字是%dn”,n%10); ,阅读程序 习题2,28,#include void main() int a=6;while(a-)printf(“%d”,-a);printf(“n”); /改为int a=7;结果如何?,阅读程序 习题3,