第六章循环结构程序设计汇总_第1页
第六章循环结构程序设计汇总_第2页
第六章循环结构程序设计汇总_第3页
免费预览已结束,剩余46页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、1个球投进箱子、取 2个球投进箱图6-1刀求和计算流程图第六章循环结构程序设计本章学习目标:掌握while语句及其应用掌握for语句及其应用掌握do-while语句及其应用掌握break、continue语句及其应用6. 1从刀求和说起在一个数据集中找出满足特定条件的数据、方程求根、数据排序、定积分计算等许多典 型的数据处理功能的实现中大都需要循环结构,没有循环结构,我们几乎不能使用计算机解 决任何复杂的问题,可见循环结构程序的重要性。本节讨论什么是循环结构以及为什么需要 循环结构,其他章节讨论 c语言循环结构的表示方法以及如何应用循环结构解决实际问题。 循环的概念很简单:一个操作被重复执行若

2、干次就是循环。引入循环的原因同样简单,就是 因为解决实际问题的需要。仔细观察一下我们的日常工作,大多与循环有一定的联系,学生 每天重复的事情是上课;会计每天重复的事情是记账;医生每天重复的事情是治病;总之我 们日常从事的工作许多都是重复,实际上就是循环,这里的重复不是机械地重复。让我们从 一个简单的问题说起,如果我们需要计算s=1+2+3+100,最简单的方式就是利用公式计算出结果,现在我们对这个问题加一点限制,首先不允许使用计算公式,然后给你一个大箱子和一大堆小球,请你利用这些道具完成上述计算,你会如何算出1+2+3+100的结果呢?我们可以这样进行,首先将箱子倒空,然后依次取 子、取3个球

3、投进箱子,如此进行下去,直到 取100个球投进箱子,这时箱子里球的数量就 是前100个数的累加和。这一过程可以表示成 如下算法:S1: sum 0S2:让i从1变到100,每次加1,重复执行 S3、S4S3: t iS4: sum sum+iS5: 输出sum图6-1就是该算法的流程图表示形式。在上述算法中,“ t i,sum sum+t,i i+1 ” 操作是一个需要被重复执行的操作,当 i=1时 执行一次、当i=2时执行一次、当i=3时执行一 次、当i=4时执行一次、 、当i=100时执行一次,该操作一共被执行了100次,被重复执行的操作成为循环体。根据算法我们可以写出 计算机程序,然后再

4、计算机上运行程序从而获得问题的解。对于上述问题求解方式读者可能会存在这样的一些疑问:(1)为什么不直接使用计算公式n*(n+1)/2直接算出计算结果? ( 2)算法6-1中的操作“ t i”是不是多余的操作,为什么 不使用"sum sum+i”直接将i的数值累加到sum中呢?第一个问题的回答是这样的,这里我们是试图使用简单问题来说明一种问题求解思路,而不是说这个问题必须使用这样的方式求解,如果使用更加复杂的问题来说明这种问题求解 方法,并不能对阐述问题求解方法带来任何帮助,相反可能不利于理解。关于第二个问题,算法中的操作“t i,sum sum+i ”在实际使用时完全可以合并成“ s

5、um sum+i ”,那么我们为什么要多此一举呢?这是因为我们希望把这个算法当做一个更加普遍的问题求解算法的基础,看一下这样做的好处吧,如果把:“t i”修改为:“t 2 x i”那么算法将实现计算sum=2+4+198+200,如果把:“t i ”修改为:“t 2x i-1 ”,那么算法将实现计算sum=1+3+197+199,如果把:“t i ”修改为:“t f(i)”,那么算法将实 现计算sum=f(1)+f(2)+f(3)+f(199)+f(200),这里f(i)表示利用i计算出一个函数值,这就 是为什么在算法中使用了一个看起来“多余”的操作的原因。这个刀求和的问题是计算机程序设计的一

6、个及其重要的问题,图6-1表示的问题求解算法可以看做是一个可以看做是一个累加和问题求解的“刀求和原型算法”,怎么样理解这个“原型算法”呢?让我们来看几个世纪应用中经常遇到的一些问题:平均值的计算:nXi标准差计算:n_s2(n 1) i(Xi X)21级数计算:nf (x) f (X0)(X X0)i4)定积分计算:bs f (x)dxai 0n 1f (a i h) h,h (b a)/ni 0上述问题的共同特点是什么?那就是它们都是刀求和,如果使用算法求解这些问题,都 可以将图6-1表示的算法通过简单的变化而获得相应问题的求解算法,从算法角度看,它们 的差别就是t的计算方法不同,因此读者务

7、必要将图6-1所表示的算法给予足够的理解,真正理解了这个算法之后,对于很多问题的求解将是非常有帮助的,这就是为什么把这个算法 称为“原型算法”的原因,这也是我们为什么强调这个刀求和算法原因,对于上述的几个问 题的具体求解算法将在本章的后续部分将予以介绍。有了算法之后,接下来就是使用计算机语言书写程序,因为算法中存在着重复操作,因此需要有表达这种重复操作的C语言语句,C语言提供了三种表达循环结构的循环语句,这三种语句是while循环语句、for循环语句和do-while循环语句,分别用于表达不同的循环结 构。6. 2 C语言循环结构621. while 循环在2.3节中我们引进了当型循环,在C语

8、言中,当型循环也叫while循环,是一种非常常见的循环方式,这种循环的基本结构及其C语言的表示如图6-2所示:OP图6-2当型循环结构图6-2的伪代码形式也已表示成:While expr doOPEnd while图6-2对应的C语言形式是:while(expr)OP;中文含义是:当expr满足时,重复做OP操作这里expr表示条件,条件可以是:关系表达式 逻辑表达式 算术表达式表达式的真假含义与判断结构中条件的含义相同,再次提醒读者注意的一点是当条件为一算术表达式时,如果算术表达式的计算结果不是0则表示为真,如果算术表达式的计算结果为0则表示为假,图6-1中的流程图清楚地表达了循环的含义,只

9、要条件C满足(计算结构为真),则执行OP操作,执行完OP操作后再次判断条件是否满足,只要条件满足就继续执行OP操作,因此OP操作可能被重复执行若干次,循环语句结束的条件是条件C计算结果为假,循环体OP可以是:C语言语句或函数复合语句另一循环语句(见复杂循环结构) 空语句初学者常常会把 “while( expr ) OP; ”和“ while( expr ) ; OP; ”混淆,前者的循环体为 OP, 后者的循环体为空语句,OP不是while语句的循环体。/*一个简单的 while循环程序*/#i nclude "stdio.h"main ()int i;i=1;while(

10、i<=10)printf("%dn",i); i+;黑体字表示的是循环语句,本章的程序中的黑体字均表示循环语句,程序的输出结果是:12345678910 对于上述程序,请读者回答如下问题:1) 循环语句结束后,变量 i 的数值是多少?2) while 语句的循环体是什么?3) 如果“ i+ ”改为“ i=i+2 ”,程序的输出结果是什么?4) 如果“ printf("%dn",i); i+; ”改为“ i+;printf("%dn",i); ”,程序的输出结果是什 么?再看下面的类似的程序:#include "stdi

11、o.h"main()int i;i=1;while(i+<=10) printf("%dn",i);程序的输出结果是:234567891011为什么第一个输出结果是2而最后一个输出结果是11呢?原因是当i=1时,i+<=10计算结果为真,但完成次计算后变量i的值已经变为2 了,因此输出第一个数据为2,同样的道理当i的值为10时,i+<=10计算结果为真,完成计算后i的值变为11 了,所以输出结果为11.,当i的值为11时,i+<=10计算结果为假,循环语句结束,但完成计算后i的值变为12了,所以整个循环语句结束后,变量i的值是12。循环在存

12、在循环结构的问题求解算法中,普遍存在图6-3所示的结构。为此人们设计了专门图6-3常见的循环形式用于描述这种循环结构的C语言语句,这就是for循环语句。图6-8对应的C语言循环语句的格式是:for(expr1;expr2;expr3)OP;其中expr1、expr2和expr3为三个 C语言表达式,OP 为C语言语句。图6-3清楚地描述了这个循环语句的执行过 程,用自然语言描述的for语句的执行过程是:S1:计算 expr1S2:计算expr2,如果结果非0 (为真),则转向S3,否 则结束循环语句S3:执行0PS4:计算 expr3S5:转向S2显然这个过程也可以使用while语句表示,图6

13、-3的while语句表达形式如下:expr1;while(expr2) OP;expr3;for语句具有很强的表达能力,使用for需要注意:(1)expr1和expr2通常是赋值表达式,使用其他的计算表达式一般没有意义,expr2通常是循环控制表达式,表示循环进行的条件,条件不满足(为假)则for语句执行结束。(2)expr1、expr2和expr3三个表达式均可以省略,需要注意的是如果 expr2省略,则表示expr2永远为真,如果循环体OP中没有结束循环的控制,将形成死循环。(3)语句0P可以是基本的 C语言语句,也可以使复合语句,甚至是另一循环 语句。一种典型的for语句的用法是:for

14、(i=1;i <n ;i+)S;其执行过程是当i=1时,执行一次S; i=2时,执行一次S; i=3时,执行一次S; i=n时,执行一次S; i=n+1时,for循环语句结束,整个循环语句中 S共执行了 n次。这个 循环语句也可以这样理解:让 i从1变到n每次加1,重复执行So循环do-while 循环结构也是常用的一种循环表达形式,其流程图形式如图6-41所示。对应的C语言表达形式如下:doOP;while(expr);Do-while循环的伪代码形式可表示为与C语言类似的形式:DoOPWhile expr这里expr表示循环控制条件, 它可以是任何 C语言表达式,当expr为一算术表

15、达式时, 计算结果非0表示真,为0表示假,0P表示循环体,循环体可以是 C语言的语句或者符合语 句,也可以是另一循环语句, do-while 语句的执行过程是:(1) 执行循环体 0P(2) 计算表达式 expr(3) 如果表达式expr为真,则转向(1),否则结束循环语句由于是限制性循环体后进行判断,因此,在do-while循环中,循环体 0P至少被执行一次,而while循环是先判断后执行循环体,所以 while循环的循环体 OP最少被执行0次, 假设s和i都是整数,对比下面两个程序段:s=0;s=0;i=15;i=15;while(i<=10)doi+; i+; s=s+i;s=s+

16、i;while(i<=10);左边的程序段循环语句(while语句)循环结束后,变量s的值是0,而右边的程序段循环语句结束后,变量 s的值是16o624三种循环结构之间的关系c语言可以使用三种不同的循环语句来表达循环,不同的结构可根据需要选择适当的循环语句来表示,但每种循环语句都可以用其他的循环语句替代,他们之间是可以相互转换的。例如对于 while语句,可以用另外两种语句表示。例如while循环语句:while(expr)OP;可表示为:或者for( ;expr; )if(expr)OP;DoOP;while(expr);同样对于for语句:for(exp1;exp2;exp3)OP;

17、可以表示为:或者exp1;exp1;while(exp2)if(exp2)OP;doexp3;OP;exp3;While(exp2);对于do-while语句,同样可以用另外两种表达形式来表示,总之任何一种循环语句,可以使用另外两种循环语句表示。从逻辑上说,只需要一种表达形式就够用了,但实际使用时, 不同的结构都有比较适合的表达形式,应选择容易理解的表达形式。例6-1计算并输出1+2+3+100。图6-5表示了累加计算的基本流程,6.1节我们强调了这个算法的重要性,现在的任务是将该算法使用 C语言表示出来,构成一个C 语言程序。使用for语句实现循环是最为简单明了的 一种表达形式,for循环语

18、句的格式是:for(expr1;expr2;expr3)OP;对比for循环结构示意图6-3,可以看出:expr1对应着“ i 1 ” expr2 对应着 “ i < 100” expr3 对应着 “ i i+1 ” OP对应着“ s s+i” 基于for循环实现的C语言程序如下:#include <stdio.h>main()int s,i;s=0;for(i=1;i<=100;i+)s=s+i; printf("%dn",sum);上述表达形式是最自然的一种表达形式,其含义是:当i=1时,执行s=s+i,当i=2时,执行s=s+i,当i=3时,执

19、行s=s+i, ,当i=100时,执行s=s+i,从而使得变量s中最后存储的是前100个数的刀和。如果使用while循环表示上述循环结构,则循环控制条件expr为"i < 100”,循环体OP为“ s s+i;i i+1 ”,基于 while 循环实现的 C 语言程序如下:#include "stdio.h"main()int i;s;s=0;i=1;while(i<=100)s=s+i;i+;printf("%dn",s);程序的输出结果是:5050仔细分析上述程序,请读者回答如下问题:2) 如果将“ i<=100”改为:“

20、 i<=200 ”,程序的运行结果是什么?3) 如果将“ s=0;i=1; ”改为:“s=0,i=0; ”,程序是否正确?4) 如果将“ i=1”改为:“i=2”,程序的运行结果是什么?5) 如果将“ i+ ”改为:“ i=i+2 ”,程序的运行结果是什么?6) 如果将“ s=0;i=1 ”改为:“i=1 ”,程序的运行结果是什么?7) 如果要计算1+2+3+10000,程序改如何修改?基本的累加和算法是一个极为重要的算法,许多问题的求解算法都可以通过这个算法的 简单变化得到。我们看一些简单的变化情况:1) 计算1+1/2+1/3+1/99+1/100,只需将算法中的“ s s+i”改为

21、“ s s+1/i”2) 计算 1+1/(2*2)+1/(3*3)+ +1/(99*99)+1/(100*100),只需将算法中的“ s s+i”改 为“ s s+1/(i*i) ”3) 计算 1+3+5+ +97+99,只需将算法中的“ i i+1 ”改为“ ii+2”4) 计算 1/(1*2)+1/(2*3)+ +1/(99*100)+1/(100*101),只需将算法中的“ s s+i ”改为“s s+1/i/(i+1) ”也可以使用 do-while 循环语句书写,程序如下:/*do-while 循环实现的累加 */#include "stdio.h"main()i

22、nt sum,i;sum=0;i=1;dosum+=i;i+;while(i<=100); printf("%dn",sum);死循环当循环条件永远为真时,循环语句将永远不能结束,我们把这种情况成为死循环。死循 环常常是我们需要避免的,由于C 语言不进行数据越界处理,不小心就会形成死循环,很多情况可能造成循环条件永远满足,几种常见的情况是:( 1)循环条件为常数,而循环体中没有结束循环的语句(见循环控制),例如:int x=0;while(1)x+;(2)程序书写格式出现错误导致的死循环,例如:s=0;i=1;while(i<100);s+=i;i+;这个循环语

23、句的循环体为一个空语句,因此变量 i 的值将永远为 1,不可能结束循环。(3)使用不可能达到的数值作为循环控制条件,例如:char ch=65;while(ch<300)ch+;字符类型的变量时一个单字节的变量,其数值不论如何变化,都不可能达到300 ,所以形成死循环。看下面的例子:float a,x=0;a=0.1;while(x!=1)x=x+a;这个程序段也将导致死循环,这似乎有点奇怪,按照常理 x 每次增加 0.1,增加 10 次就会变为 1 的,但实际上 x 永远不可能为 1,原因在于 0.1 这个实数不能使用有限位二进制精确表示, 所以看起来十分精确的十进制数 0.1 实际上

24、在内存存储的却是一个不精确的数值,因为我们 不能使用有限位二进制精确地表示0.1,从而导致了死循环, 在编写数值计算方面的程序时需要特别注意这个问题,读者需要质疑的是在十进制可以精确表示的数在二进制不一定能使用 有限位二进制精确表示。6 3 基本循环结构举例例 6-2 从键盘输入 10 个整数,求出这 10 个数中的最大数。求解分析:使用变量 max 表示 10 个数中的最大数,假设第一个数是最大的,然后依次输入 后续的数据,对每个输入的数据,将其与 max 比较,如果输入的数比 max 大,则将其保存在 变量 max 中,这样所有的数输入完后,变量 max 中博爱村的就是 10 个数中的最大

25、数,实现 的算法如下:Input xmax xFor i=2 to 10 doInput xIf x>max thenmax xEnd ifEnd forPrint max基于上述算法编写的 C 语言程序如下:#include <stdio.h>main()int x,max,i;scanf("%d",&x);max=x;for(i=2;i<=10;i+)scanf("%d",&x);if(x>max)max=x;printf("max=%dn",max);getchar();getcha

26、r();运行程序输入:23 56 19 527 768 453 123 90 26 11 程序输出:max=768问题:( 1)如果需要输出第几个输入的数是最大数,程序如何修改?(2)如果需要同时计算出最大数和最小数,程序改如何修改?例6-3输入两个正整数 m和n,求m和n的最大公约数。求解这个问题通常有两种方 法,一是根据最大公约数的定义设 计算法求解问题,二是采用著名的 最大公约数算法 辗转相除 法。图6-6给出了基于最大公约数 定义的求解算法,在例2-7中我们假设m>=n,主要是为了便于理解, 实际上这一假设可以取消。图6-6算法的伪代码形式是:In put m,ni nWhile

27、 m mod i<>0or n mod i<>0 doi<-i-1End whilePrint i实现该算法的 C语言程序如 下:#i nclude "stdio.h"main ()in t m,n ,i;sca nf("%d%d", &m,&n); i=n;while(m%i!=0 | n %i!=0)i-;prin tf("%dn" ,i);运行程序,当输入 35 42时,程序输出结果是:7注意循环结束的条件是出现 m和n能同时除尽的i,由于i是从大向小变的,所以这时的 i 就是最大公

28、约数。另外一种方法是让i从小向大变化,将 m和n能同时除尽的i记录下来,那么最后一次被记录下的 i的值就是最大公约数,根据这一思路编写的程序如下,请读者仔 细对比两者的差异在这个程序中,增加了一个变量r,用于记录m和n能同时除尽的i,因为变量i是从小向大变化的,因此最后记录在r中的数就是最大公约数。#include "stdio.h" main ()int m,n,i,r;scan f("%d%d",&m,&n);i=1;while(i<=n)if(m%i=O && n %i=0 )r=i;i+;prin tf(&q

29、uot;%dn",r);现在我们来讨论著名的辗转相除法算法,假设m>=n,函数gcd(m,n)表示m和n的最大公约数,令c=gcd(m,n),即m=k1*c,n=k2*c,m=k*n+r,r是m除以n的余数,显然如果 r=0 的话,那么m和n的最大公约数必为 n,如果r不为0,那么:m=k*n+r:>k1*c=k*k2*c+r1-r=(k1-k*k2)*c ,即c也必然是n和r的一个公约数,而 c1=gcd(n,r)是n和r的最大公约数,所以:c1>=c=gcd( m,n)同理如果 c1=gcd(n,r),必有 n=k3*c1, r=k4*c1,因为 m=k*n+r

30、,所以:m=k* n+r=k*k3*c1+k4*c1=(k*k3+k4)*c1即c1必然是m和n的公约数,而c是m和n的最大公约数,所以c1<=c因此 c1=c,即卩 gcd(m,n)=gcd(n,r)。辗转相除法算法正是基于这样的原理来设计的,流程图表示的算法如图6-7所示。图6-7基于辗转相处法的最大公约数算法基于辗转相除法的最大公约数计算方法 的伪代码表示的算法如下:In put m,nr m mod nWhile r<>0 dom nn rr m mod nEnd whilePrint n对应的C语言程序如下:#i nclude "stdio.h"

31、 main ()int m,n,r;scanf("%d%d",&m,&n);r=m%n;while(r!=0)m=n;n=r;r=m%n;printf("%dn",n);运行程序,输入 26 65 时,程序的输出是:13需要说明的一点是关于这个算法的许多资料的描述时, 对于 m<n 时都进行数据交换, 实际上 这是不必要的,下面是取自其他有关书籍中的辗转相除法程序,读者体会其中的差异。#include "stdio.h"main()int m,n,r,t;scanf("%d%d",&m

32、,&n);if(m<n)t=m;m=n;n=t;r=m%n;while(r!=0)m=n;n=r;r=m%n;printf("%dn",n);运行程序,输入 26 65 时,程序的输出是:13例 6-4 输入一个大于 2 的正整数,判断该数是否为素数,如果是素数则输出“prime ”,否则输出“ not prime! ”,一个数如果不能被除了 1 和它本身之外的任何自然数整除的话,该 数就是素数,换句话说除了 1 和它本身以外,素数不再有别的约数。求解思路:假设n是需要判断的整数(n>2),只需要让n依次除以2、3、n-1,如 果 n 能除尽其中的某一个

33、或者几个的话,那么 n 必然不是素数,否则的话, n 就是素数。我 们可以使用一个变量(比如 flag )来表示 n 是否能被某个数除尽, flag=0 表示 n 能除尽某个 数,即n不是素数,flag=1表示n不能除尽2、3、n-1中的每一个数,即n是素数。实 现素数判断的算法如图 6-8 所示。开始算法的伪代码形式如下:In put nFlag 1,i2While i<n doIf n mod i=0 thenFlag 0End ifi i+1End whileIf Flag=1 thenPrint prime ”ElsePrint not prime ”End if基于上述算法编写

34、的C语言程序如下:#include "stdio.h"main ()int n,flag,i;sca nf("%d",&n);flag=1;i=2;while(i<n) if(n%i=0) flag=0;i+; if(flag=1) printf("primen");elseprintf("not primen"); 运行程序,输入 31 时程序输出 prime 输入 39 时程序输出: not prime请读者回答如下问题:1) “if(flag=1 ”是否可以改为“ if(flag) ”?为什么?

35、2) 如果将程序的“ flag=1 ”改为“ flag=3 ”,程序还需要修改哪里?3) 如果程序要求输出是“ 31 is a prime”、“ 39 is a not prime ”这样的形式,输出函数需要 进行怎样的修改?关于算法的改进: 程序的循环变量i是从2变到n-1,这样循环体被执行了 n-2次,实际上变 量i只需要从2变到sqrt(n)就够了,因为如果n=a*b的话,那么a和b中至少有一个小于 sqrt(n), 因此i从2变到sqrt(n)就足够了。改进后的程序如下:#include "stdio.h"#include “math.h”main()int n,f

36、lag,i;scanf("%d",&n);flag=1;i=2;while(i<=sqrt(n)if(n%i=0)flag=0;i+;if(flag=1)printf("primen");elseprintf("not primen");还有什么可以改进的吗?实际上执行循环语句时需要进行n-1 次判断 i<=sqrt(n) ,每次判断都需要计算sqrt(n),实际上可以在循环之前将sqrt(n)的值保存到变量 m中,循环中使用while(i<=m)就行了,这样执行效率更高些,读者可以自行完成这种改进,更进一步

37、实际上不 需要调用函数sqrt( n)也可以实现循环次数不超过sqrt( n)次。6. 4循环结构应用6. 4. 1刀求和与循环问题:从键盘输入10个数,求出这10个数的平均值,平均值就是累加和除以数据个数:刀求和是一类和普遍的问题,我们通过几个具体问题来了解这类问题的求解方法。1.计算平均值Xi这个问题的求解算法可以通过图6-1的算法的一个简单的变化得到,使用x表示输入的数据,使用avg表示数据平均值,图6-9表示了计算平均值的算法,黑体字部分是对算 法6-1的修改地方。基于上述算法编写的C语言程序如下:#i nclude <stdio.h>main ()float x,sum,

38、avg;int i;sum=0;for(i=1;i<=10;i+)sca nf("%f", &x);sum=sum+x;avg=sum/10;prin tf("average=%fn",avg);运行程序输入:1 2 3 4 5 6 7 8 9 10程序输出:average=5.500000使用while循环语句表达的程序如下:#i nclude <stdio.h>mai n()float x,sum,avg;int i;sum=0;i=1;while(i<=10)sea nf("%f", &x

39、);sum=sum+x;i+;avg=sum/10;prin tf("average=%fn",avg);请回答如下问题:CD如果上述程序的for语句:for(i=1;i<=10;i+)改为:for(i=0;i+)空白处该填写什么?C如果把左边程序中的“ sum=0;i=1; ”取消,那么程序需要做什么样的修改?3如果需要计算20个数的平均值,程序改如何修改?2.级数求和计算问题:利用公式:1 1 1e 11-计算自然数 e的值,计算进行到最后一项数据2!3!n!110 6为止。n!实际上这也是一个刀求和的问题,参与累加的数据中包含了阶乘数据,阶乘计算本身又需要循环,

40、怎样方便地计算车每项的阶 乘数据呢?实际上 k!=(k-1)!*k ,而(k-1)! 又刚好是上一次计算的阶乘, 所以只要利用 上次结成计算的结果就可以算出下次阶乘。 这样可以避免多次的循环, 自然运行效率会 更高,阶乘的倒数计算方法类似。流程图表 示的算法如图6-10所示,这个算法也是刀 求和算法的简单变换得到的。这里t表示每次需要累加的数据项,即阶乘的倒数,当n=k时,t存储的是1/(k!), 当n=k+1时,利用t t/n计算出新的值, 这时 t=t/n=(1/(k!)/(k+1)=1/(k+1)!),刚好是需要累加的数据项,显然数据e和t图6-10计算自然数的流程图是实数数据。完整的C

41、语言程序如下:#include "stdio.h"main()int n;float e,t; e=1.0;t=1.0;for(n=1;t>1e-6;t=t/n)e=e+t;n+; printf("%fn",e);程序的输出结果是:2.718282上述程序使用 while循环表示更加容易理解,基于while循环编写的C语言程序如下:#include "stdio.h"main()int n;float e,t;e=1.0;t=1.0;n=1;while(t>1e-6)e=e+t;n+;t=t/n;printf("

42、%fn",e);级数计算是一个非常典型的累加和计算问题,任何函数度可以表示成一个级数的形式,实际上就是一个多项式的累加和,没有学过级数的读者只要把级数当做一个累加和问题就可n以了,不影响理解。对于累加和问题 saia1 a2 an ,可以采用如下算法:i1S0i1t a1While c(t)=true doSS+tii+1t计算aiEnd whilePrint S这里c(t)表示循环结束条件,c(t)=true不满足循环条件,循环结束,需要注意的是n if(x)exx 1 xi 0 i!我们的任务是设计一个程序,对任意输入的表示满足循环条件,执行循环体,c(t)=false 表示ai

43、常常可以由ai i算出,例如对于下面的函数:23nXXx2!3! n!X,计算出函数f(x)的值,当10 6时停止累加计算,设s表示累加和,t表示每一项数据,可以设计这样的算法:In put xs 0;i 0t 1While t>1e-6 doss+t/*将数据项累加到s中*/i<-i+1tt*x/i/*计算下一项数据*/End whilePrint s根据上述算法编写的C语言程序如下:#i nclude "stdio.h"main ()float x,s,t;int i;sca nf("%f", &x);s=0;i=0;t=1;wh

44、ile(t>1e-6)s=s+t;i+;t=t*x/i;prin tf("%fn",s);运行程序输入1时,程序输出结果是:2.718282上述程序当x=1时,就是计算自然数 e,程序结构书基本一致。3. n的近似计算问题:利用公式一 14计算的近似值,直到最后一项数据的绝对值小于10 5 。求解分析:这是累加和的计算问题,参与累加的每项数据 可以通过如下数据获得:n: 13t=1/ n: 1 sig n: +1 p=sign*t :图6-11表示了计算do-while 循环结构,1/5+11/7-11/3-1-1/31/5 -1/7的流程图算法,这个循环是典型的因此

45、使用 do-while循环语句表示图6-11 所示6-11算法中的循环结构时最为自然的,基于图 的算法编写的C语言程序如下:#in elude "stdio.h"main ()float sum,t,p;int n ,sig n;sum=0;sig n=1;t=1.0;n=1;dop=sig n*t;_sum=sum+p;n=n+2;sig n=-sig n;t=1.0/n;while(t>1e-6);prin tf("%fn",4*sum); 程序的输出结果是:3.141594.-/*循环体*/4.定积分计算根据定积分定义,函数f(x)在区间a,

46、b上的积分定义为:bs f(x)dxanf(a i h) h h (f(a) f(a h) f(a 2h)i 0f(a n h)图6-12给出了定积分的示意图:其中h=(b-a)/n ,当n 时,s就是定积分的值,定积分的计算需要求原函数,如果求不出原函数,我们常常使用近似方法来计算定积分的近似值,即设定一个足够大的n,使用上面的公式来计算定积分的近似值。实际上定积分被看做n个小矩形面积之和 s=s1+s2+s3+sn,其中 s1=h*f(a)、s2=h*f(a+h)、sn=h*f(a+(n-1)*h),定积分的近似有若干种方法,这里我们讨论两种:矩形法:将每个小面积近似看做一个矩形梯形法:将

47、每个小面积近似看做一个梯形a图6-12定积分计算示意图对于定积分的近似计算,理论上说n越大,计算结果越准确,因为 n趋于无穷大时就是定积分的精确值。定积分近似计算也是刀求和,因此也可以通过图6-1表示的算法的简单变换得到,基于矩形法的算法表示为:In put a,b,ns 0h (b-a)/nFor i=0 to n-1 step 1 dofx f(a+i*h)s s+h*fxend forprint s例6-5用矩形法近似计算函数f(x)=x*x 在0,3上的定积分。基于上述算法编写的程序如下:#i nclude "stdio.h"main ()float a,b,h,s

48、,fx;int i,n;sca nf("%f%f%d n",&a, &b, &n);s=0;h=(b-a)/n;for(i=0;i<n;i+)fx=(a+i*h)*(a+i*h); /* 计算 f(a+i*h) 的值 */ s=s+h*fx;printf("s=%fn",s); 运行程序当输入 0 3 1000 时,程序输出: s=8.986502实际上定积分的精确值是 3.0 。表 6-1 给出了不同的 n 的值与计算精度的关系: 表 6-1n abs1000038.9865022000038.9932473000038.

49、9955024000038.9966325000038.9973016000038.9977537000038.9980658000038.9983199000038.99850410000038.998650可以看出,随着 n 的增大,计算结果更加逼近于定积分的实际值( 9.0 )。 使用矩形法计算定积分的近似值时,由于使用小矩形近似代替小区间的积分面积,所以产生 误差就比较大,每个小面积使用一个梯形面积来近似表示似乎是个更加精确地方法,梯形面 积比矩形面积更加接近于实际面积。基于梯形法的定积分计算算法描述如下:Input a,b,ns0h (b-a)/nFor i=0 to n-1 ste

50、p 1 dofx1 f(a+i*h)fx2 f(a+(i+1)*h)s s+(fx1+fx2)*h/2/* (fx1 + fx2) *h /2*/end for /*(上底 +下底) * 高 /2*/print s例 6-6 用梯形法近似计算函数 f(x)=x*x 在 0,3 上的定积分。#include "stdio.h"main()float a,b,h,s,fx1,fx2;int i,n; scanf("%f%f%dn",&a,&b,&n);s=0;h=(b-a)/n; for(i=0;i<n;i+)fx1=(a+i*

51、h)*(a+i*h);fx2=(a+(i+1)*h)*(a+(i+1)*h);s=s+(fx1+fx2)*h/2; printf("s=%fn",s);运行程序当输入 0 3 1000 时,程序输出:s=9.000003 显然梯形法比矩形法计算的精度更加精确(接近 9.0 )。64 2 穷举与循环一类非常普遍的问题是在一个给定的有限数据集合S=x1,x2,x3, xn中,找出满足特定条件的所有数据,所谓穷举就是对数据集合中的每个数据元素,判断是否满足给定条件, 穷举算法的基本思路是:对于 S 中的每个数据元素 xi ,重复做如果 xi 满足给定条件,则输出xi例 6-7 求

52、出 100 以内的所有除以 7 余数为 2 的数。这个问题非常简单,S=1,2,3,100,求解思路是:对于1100的每一个数n,重复做如果 n mod 7=2 则输出 n对应的 C 语言程序如下:#include <stdio.h>main()int n;for(n=1;n<=100;n+)if(n%7=2)printf("%dn",n);运行程序会输出所有除 7余 2的数,请问如果循环体不使用 if 语句,只使用 printf 函数输 出数据,程序改如何修改?请看下面的程序:#include <stdio.h> main()int n; f

53、or(n=2;n<=100;n+=7) printf("%dn",n);这个程序与前面的程序输出同样的结果,但是没有使用 if 语句。例 6-8 求出 100999 之间的所有水仙花数。 如果一个数的个十百位的立方和与该数相等, 则成该数为水仙花数。数据集合S=100,101,102 ,,999,求解思路是:For n=100 to 999 step 1 do an 的个位bn 的十位cn 的百位d a*a*a+b*b*b+c*c*c if d=n then print nEnd for 如何取出一个数的个十百位数呢?有若干不同的取法,这里给出其中的一种取法: n 的

54、个位 =n%10 n 的十位 =(n/10)%10 n 的百位 =(n/100)%10 n 的千位 =(n/100)%10 n 的万位 =(n/10000)%10完成的 C 语言程序如下: #include <stdio.h> main()int n,a,b,c,d; for(n=100;n<1000;n+)a=n%10; b=(n/10)%10;c=(n/100)%10; d=a*a*a+b*b*b+c*c*c;if(d=n) printf("%dn",n);程序运行的输出结果是:153370371407当一个方程的变量个数大于 1 时,方程组的解就不是

55、一组唯一解, 会产生若干方程的解。 例如对于方程 x1+x2=100 要求求出该方程的所有正整数的解,方程的解是 (1,99) 、 (2,98) 、 (3,97)、(99,1),共99组方程的解。对于一个不定方程f(x1,x2,xn)=k,可行解的空间通常是很大的,我们的任务是在这个可行解空间中,找出满足方程式的解。我们以 f(x1,x2)=k 为例讨论求解不定方程的算法,基本思路非常简单,就是: 对于可行解中的每一组数据( x1,x2 )如果 f(x1,x2)=k 则输出 x1,x2因此求解不定方程时,只要我们能够确定一个有限的可行解范围,我们就可以方便地求出所 有满足方程式的解,可行解的范围根据具体问题通常可以比较方便地确定,需要注意的是如 果可行解的空间特别巨大, 则穷举方法是不适用的, 因为穷举所有可能需要大量的计算时间, 怎样理解特别巨大呢?一个简单的判断标准时如果可行解的数量需要使用一个指数函数(比 如 2n )表示的话,那么就不适合使用穷举方法,除非n 很小。下面我们通过具体例子讨论不定方程的求解。例 6-9 求满足方程 7*x1+3*x2=84 的所有大于 0 的正整数解。 问题分析:根据问题可知, x1 的最小

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论