收藏 分享(赏)

第5章循环控制.ppt

上传人:kpmy5893 文档编号:8464681 上传时间:2019-06-29 格式:PPT 页数:55 大小:463KB
下载 相关 举报
第5章循环控制.ppt_第1页
第1页 / 共55页
第5章循环控制.ppt_第2页
第2页 / 共55页
第5章循环控制.ppt_第3页
第3页 / 共55页
第5章循环控制.ppt_第4页
第4页 / 共55页
第5章循环控制.ppt_第5页
第5页 / 共55页
点击查看更多>>
资源描述

1、第 5 章 循 环 控 制,5.1 概 述循环(或称重复)是计算机解题的一个重要特征。计算机运算速度快,最宜于用于重复性的工作。在程序设计时,人们也总是把复杂的不易理解的求解过程转换为易于理解的操作的多次重复。这样,一方面可以降低问题的重复性,减低程序设计的难度,减少程序书写以及输入的工作量;另一方面可以充分发挥计算机运算速度快、能自动执行程序的优势。(如求1100的累加和)循环结构是结构化程序设计的基本结构之一,它和顺序结构、选择结构共同作为各种复杂程序的基本构造单元。因此熟练掌握选择结构和循环结构的概念及使用是程序设计的最基本的要求。(1)用goto语句和if 语句构成循环;(2)用whi

2、le语句;(3)用do-while语句;(4)用for语句。,5.2 goto语句以及用goto语句构成循环,goto语句为无条件转向语句,它的一般形式为goto 语句标号;语句标号用标识符表示,它的定名规则与变量名相同,即由字母、数字和下划线组成,其第一个字符必须为字母或下划线。不能用整数来做标号。例如:goto label_1;是合法的,而 goto 123;是不合法的。结构化程序设计方法主张限制使用goto语句,因为滥用goto语句将使程序流程无规律、可读性差。但也不是绝对禁止使用goto语句。一般来说,可以有两种用途:(1) 与if语句一起构成循环结构;(2) 从循环体中跳转到循环体外

3、,但在c语言中可以用break语句和continue语句跳出本层循环和结束本次循环。goto语句的使用机会已大大减少,只是需要从多层循环的内层循环跳到外层循环外时才用到goto语句。但是这种用法不符合结构化原则,一般不宜采用,只有在不得已时(例如能大大提高效率)才使用。,例:用if语句和goto语句构成循环,求 。main( ) int i, sum=0;i=1;loop:if (i=100) sum=sum+i;i+;goto loop; printf(“%d“,sum);运行结果:5050这里用的是“当型”循环结构,当满足“i=100” 时执行花括弧内的循环体。,5.3 while语句wh

4、ile语句用来实现“当型”循环结构。其一般形式如下:while(表达式) 循环体语句当表达式为非0值时,执行while语句中的内嵌语句。其流程图见图。其特点是:先判断表达式,后执行语句。,执行过程:在执行while语句时,先对条件表达式进行计算,若其值为真(非零),则执行循环体中的语句,否则跳过循环体,而执行该结构后面的语句。在进入循环体后,每执行完一次循环体语句后,再对条件表达式进行一次计算和判断当发现条件表达式的值为0时,便立即退出循环。 说明: (1)先对表达式计算,然后判断条件。循环语句可能一次也不执行。 (2)注意边界值的设定。边界值是使条件表达式正好为真或为假的值,或者说在真和假的

5、边界上。如:int i=0; 和 int i=0;while (i3) while (i=3) printf(“%d”,i); printf(“%d”,i);i=i+1; i=i+1; ,(3) 循环体如果包含一个以上的语句,应该用花括弧括起来,以复合语句形式出现。如果不加花括弧,则while语句的范围只到while后面第一个分号处。(4) 在循环体中应有使循环趋向于结束的语句,避免while陷入无限循环。在下例中循环结束的条件是“i100”,因此在循环体中应该有使i增值以最终导致i100的语句,今用“i+;”语句来达到此目的。如果无此语句,则i的值始终不改变,循环永不结束。,例:用while

6、语句求1100的累计和。N-S图:,main( ) int i=1,sum=0;while (i=100)sum+= i;i+;printf(“%dn“,sum);,5.4 do-while语句do-while语句的一般形式为:do 循环体语句while (表达式) ;它是这样执行的:先执行一次指定的循环体语句,然后判别表达式,当表达式的值为非零(“真”) 时,返回重新执行循环体语句,如此反复,直到表达式的值等于0为止,此时循环结束。do-while语句的特点是先执行循环体,然后判断循环条件是否成立。循环体至少能被执行一次。对同一个问题可以用while语句处理,也可以用do-while语句处理

7、。do-while语句结构可以转换成while结构。在一般情况下,用while语句和用do-while语句处理同一问题时,若二者的循环体部分是一样的,它们的结果也一样。但是如果while后面的表达式一开始就为假(0值)时,两种循环的结果是不同的。,例4 while和do-while循环的比较。(1) main ( ) (2) main( ) int sum=0,i; int sum=0,i;scanf(“%d”,,可以看到:当输入i的值小于或等于10时,二者得到结果相同。而当i10时,二者结果就不同了。这是因为此时对while循环来说,一次也不执行循环体(表达式“i=10”为假),而对do w

8、hile循环语句来说则要执行一次循环体。可以得到结论:当while后面的表达式的第一次的值为“真”时,两种循环得到的结果相同。否则,二者结果不相同(指二者具有相同的循环体的情况)。do-while循环是先执行循环体,后判断表达式的“当型”循环(因为当条件满足时才执行循环体)。但利用它可以方便地实现典型的“直到型”循环结构。典型的直到型(until型)循环结构是表达式为真时结束循环。因此在将do-while循环结构画成NS结构流程图形式表示的直到型循环结构时,应将条件取“反”。,5.5 for语句C语言中的for语句使用最为灵活,不仅可以用于循环次数已经确定的情况,而且可以用于循环次数不确定而只

9、给出循环结束条件的情况,它完全可以代替while语句。for语句的一般形式为:for(表达式1;表达式2;表达式3) 语句;它的执行过程如下:(1) 先求解表达式1。(2) 求解表达式2,若其值为真(值为非0),则执行for语句中指定的内嵌语句,然后执行下面第(3)步。若为假(值为0),则结束循环,转到第(5)步。(3) 求解表达式3。(4) 转回上面第(2)步骤继续执行。(5) 循环结束,执行for语句下面的一个语句。,for语句最简单的应用形式也就是最易理解的如下形式:for(循环变量赋初值;循环条件;循环变量增值) 语句 例如:for(i=1;i=100;i+) sum=sum+i; 可

10、以看到它相当于以下语句:i=1;while(i=100)sum=sum+i;i+;显然,用for语句简单、方便。对于以上for语句的一般形式也可以改写为while循环的形式:表达式1;while (表达式2)语句表达式3;,说明:(1) for语句的一般形式中的“表达式1”可以省略,此时应在for语句之前给循环变量赋初值。注意省略表达式1时,其后的分号不能省略。如for(;i=100;i+) sum=sum+i;执行时,跳过“求解表达式1”这一步,其他不变。(2) 如果表达式2省略,即不判断循环条件,循环无终止地进行下去。也就是认为表达式2始终为真。例如:for(i=1; ;i+) sum=s

11、um+i;表达式1是一个赋值表达式,表达式2空缺。它相当于:i=1;while(1) sum=sum+i;i+;,(3) 表达式3也可以省略,但此时程序设计者应另外设法保证循环能正常结束。如:for(i=1;i=100; ) sum=sum+i ;i+; 在上面的for语句中只有表达式1和表达式2,而没有表达式3。i+的操作不放在for语句的表达式3的位置处,而作为循环体的一部分,效果是一样的,都能使循环正常结束。(4)可以省略表达式1和表达式3,只有表达式2,即只给循环条件,如:for( ;i=100; ) while(i=100) sum=sum+i; 相当于 sum=sum+i;i+;

12、i+;在这种情况下,完全等同于while语句。可见for语句比while语句功能强,除了可以给出循环条件外,还可以赋初值,使循环变量自动增值等。(5)三个表达式都可省略,如:for( ; ; ) 语句; 相当于:while(1) 语句;即不设初值,不判断条件(认为表达式2为真值),循环变量不增值。无终止地执行循环体。,(6) 表达式1可以是设置循环变量初值的赋值表达式,也可以是与循环变量无关的其他表达式。如:for (sum=0;i=100;i+) sum=sum+i; 表达式3也可以是与循环控制无关的任意表达式。表达式1和表达式3可以是一个简单的表达式,也可以是逗号表达式,即包含一个以上的简

13、单表达式,中间用逗号间隔。如:for(sum=0,i=1;i=100;i+) sum=sum+i;或: for(i=0,j=100;i=j;i+,j-) k+=i*j;表达式1和表达式3都是逗号表达式,各包含两个赋值表达式,即同时设两个初值,使两个变量增值。在逗号表达式内按自左至右顺序求解,整个逗号表达式的值为其中最右边的表达式的值。如:for(i=1;i=100;i+,i+) sum=sum+i;相当于:for(i=1;i=100;i=i+2) sum=sum+i;(7) 表达式一般是关系表达式(如i=100)或逻辑表达式(如ab & xy),但也可以是数值表达式或字符表达式,只要其值为非零

14、,就执行循环体。,5.6 循环的嵌套一个循环体内又包含另一个完整的循环结构,称为循环的嵌套。内嵌的循环中还可以嵌套循环,这就是多层循环。各种语言中关于循环的嵌套的概念都是一样的。三种循环(while循环、dowhile循环和for循环)可以互相嵌套。例如,下面几种都是合法的形式:,(2) for(; ;) for(; ;),(1) while( )while( ),(3) dodo while( );while( );,(4) while( )dowhile( ); ,(5) for(; ;)while( ) ,(6) dofor (; ;) while( );,5.7 几种循环的比较(1)

15、四种循环都可以用来处理同一问题,一般情况下它们可以互相代替。但一般不提倡用goto型循环。(2) while和do while循环,只在while后面指定循环条件,在循环体中应包含使循环趋于结束的语句(如i+,或i=i+1等)。for循环可以在表达式3中包含使循环趋于结束的操作,甚至可以将循环体中的操作全部放到表达式3中。因此for语句的功能更强,凡用while循环能完成的,用for循环都能实现。(3) 用while和do while循环时,循环变量初始化的操作应在while和do while语句之前完成。而for语句可以在表达式1中实现循环变量的初始化。(4) while循环、do whil

16、e循环和for循环,可以用break语句跳出循环,用continue语句结束本次循环。而对用goto语句和if语句构成的循环,不能用break语句和continue语句进行控制。,5.8.1 break语句第4章已介绍过用break语句可以使流程跳出多分支选择结构(Switch结构) ,继续执行Switch语句下面的一个语句。实际上,break语句还可以用来从循环体内跳出循环体,即提前结束循环,接着执行循环下面的语句。如:for(r=1;r100) break;printf(“%f“,area);,5.8 break语句和continue语句,计算r=1到r=10时的圆面积,直到面积area大

17、于100为止。从上面的for循环可以看到:当area100时,执行break语句,提前结束循环,即不再继续执行其余的几次循环。,break语句的一般形式为: break;break语句的功能是把流程从所在处转向所在的循环结构或多路选择结构之后,或者说是中止执行这些结构。它不能用于循环语句和Switch语句之外的任何其他语句中。,5.8.2 continue语句一般形式为: continue;其作用为结束本次循环,即跳过循环体中下面尚未执行的语句,然后再根据循环条件是否满足,决定是否进入下一次循环。continue语句和break语句的区别是:continue语句只结束本次循环,而不是终止整个循

18、环的执行。而break语句则是结束整个循环过程,不再判断执行循环的条件是否成立。,(1) while(表达式1) if(表达式2) break;,(2) while(表达式1) if(表达式2) continue;,例:把100200之间的不能被3整除的数输出。main( )int n;for (n=100;n=200;n+) if (n%3=0) continue;printf(“%d“,n);当n能被3整除时,执行continue语句,结束本次循环(即跳过printf函数语句),只有n不能被3整除时才执行printf函数。当然,循环体也可以改用一个语句处理:if (n%3!=0) prin

19、tf(“%d“,n);用continue语句无非为了说明continue语句的作用。,5.9 程序举例,例1:设计一程序求n!main() int i,n,fac;scanf(“%d“,例2:用公式/41-1/3+1/5-1/7+求的近似值,直到最后一项的绝对值小于10-6为止。分析:本题可看作若干项累加的问题,只是累加的项的符号正负交替出现。若不考虑正负号,用下列程序段完成功能。s=0;i=1;do s=s+1.0/i;i+=2;while (1.0/i=1.e-6);为了反映各项的正负号,用k*1.0/i表示要累加的项,其中k是1或-1。i=1时,累加项是1.0/i,所以要取k=1;i=3

20、时,累加项是-1.0/i,所以要取k=-1;正负号总是交替出现。第一项为正数,故k的初值应置为1,以后每累加一项,就执行k=-k;使k的值交替为1或-1。,程序如下: main( ) int i,k;float pai;pai=0;k=1;i=1;do pai=pai+k*1.0/i;i+=2; /*下一项的分母*/k=-k; /*下一项的符号*/ while (1.0/i=1.e-6);pai=4*pai; /*求*/printf(“pai=%fn”,pai);,例3:求fibonacci 数列40个数。这是一个有趣的古典数学问题:有一对兔子,从出生后第3个月起每个月都生一对兔子。小兔子长到

21、第3个月后每个月又生一对兔子。假设所有兔子都不死,问每个月的兔子总数为多少?这个数列有如下特点:第1,2两个数为1,1。从第3个数开始,该数是其前面两个数之和。即:F1=1 (n=1)F2=1 (n=2)Fn=Fn-1+Fn-2 (n3) 算法如下图所示:,程序如下:main( ) long int f1,f2;int i;f1=1;f2=1; for(i=1; i=20; i+)printf(“%12ld %12ld “,f1,f2);if(i%2= =0) printf(“n”); /* if 保证输出4个就换行*/f1=f1+f2;f2=f2+f1;,另外,还可以:main( ) lon

22、g int f,f1,f2;int i;f1=1;f2=1;printf(“%12ld%12ld“,f1,f2); for(i=3; i=40; i+) f=f1+f2;f1=f2;f2=f; printf(“%12ld“,f);if(i%4=0) printf(“n“); ,运行结果为:1 1 2 35 8 13 2134 55 89 144233 377 610 9871597 2584 4181 676510946 17711 28657 4636875025 121393 196418 317811514229 832040 1346269 21783093524578 5702288

23、7 9227465 493035224157817 39088169 63245986 102334155,例4:判断m (m3)是否素数。所谓素数,是指除了1和m之外,没能被2(m-1)之 间的任何整数整除。我们采用的算法是这样的:让m被2到m-1 除,如果m能被2(m-1) 之中某一个整数整除,则提前结束循环,m不是素数。如果m不能被2(m-1) 之中任何一个整数整除,则m是素数。最直观的方法是:看在2m/2(2sqrt(m)中能否找到一个数将m整除,若该数不存在,则m为素数。程序如下:# include main( ) int n,m,flag=1;scanf(“%d“,,运行情况如下:

24、1717 is a Prime number,另外,还可以:让m被2到 除,如果m能被2 之中任何一个整数整除,则提前结束循环,此时i必然小于或等于k(即 );如果m不能被2k(即 )之间的任一整数整除,则在完成最后一次循环后,i还要加1,因此i=k+1,然后才终止循环。在循环之后判别i的值是否大于或等于k+1,若是,则表明未曾被2k之间任一整数整除过,因此输出“是素数”。#include main() int m,i,k;scanf(“%d“,,例4:求100200间的全部素数。在例5.8的基础上,对本题用一个嵌套的for循环即可处理。# include main() int m,k,i,n

25、=0;for(m=101;m=k+1) printf(“%d“,m); n=n+1; if(n%10=0) printf(“n“);printf (“n“);运行结果如下:101 103 107 109 113 127 131 137 139 149151 157 163 167 173 179 181 191 193 197199 n的作用是累计输出素数的个数,控制每行输出10个数据。,例5:译密码。为使电文保密,往往按一定规律将其转换成密码,收报人再按约定的规律将其译回原文。例如,可以按以下规律将电文变成密码:将字母A变成字母E,a变成e,即变成其后的第4个字母,W变成A,X变成B,Y变成

26、C,Z变成D。字母按上述规律转换,非字母字符不变。如“china!”转换为“glmre!” 。输入一行字符,要求输出其相应的密码。,#include main() char c;while(c=getchar()!=n) if(c=a 运行结果如下:china! Glmre!,程序中对输入的字符处理办法是:先判定它是否大写字母或小写字母,若是,则将其值加4(变成其后的第4个字母)。如果加4以后字符值大于Z或z,则表示原来的字母在V(或v)之后,应将它转换为AD(或ad)之一,办法是使c减26。另注意:内嵌的if语句不能写成 if(cZ| cz) c=c-26;因为当字母为小写时都满足“cZ”条

27、件,从而也执行“c=c-26;”语句,这就会出错。因此必须限制其范围为“cZ & cz & cz”即可。,循环体能否改为: while(c=getchar()!=n) if(c=a,例6:欧几里德算法:求两个非负整数u和v的最大公因子(即最大公约数)。方法(辗转相除法):比较两个非负整数的大小,将大数送入u,小数送入v。当v不等于0时,辗转使用操作: r=u%v;u=v;v=r;消去相同的因子。直到v=0时,u的值即为所求的解。 如:求32和24的最大公因子。令u=32,v=24;r=u%v=32%24=8;u=v=24;v=r=8;r=u%v=24%8=0;u=v=8;v=r=0; 所以,最

28、大公因子为8。这是一种迭代算法。迭代是一个不断用新值取代变量的旧值,或由变量的旧值递推出新值的过程。,程序如下: main() int u,v,t,r;scanf(“%d%d”,例7:百钱买百鸡。公鸡:一只5钱;母鸡:一只3钱;小鸡:三只一钱。若用100钱买100只鸡,求这100只鸡中公鸡、母鸡、小鸡各几只?分析:设公鸡为x只,母鸡为y只,小鸡为z只。根据已知可列方程:x+y+z=1005x+3y+z/3=100求解上述不定方程,需首先确定其中一个变量的值才行。根据题目给出的条件,公鸡、母鸡、小鸡数目的,大致取值范围分别是:公鸡:019母鸡:033小鸡:0100,设x=0,若y=0,则z=10

29、0-x-y,验证是否满足 5x+3y+z/3=100若y=1,则z=100-x-y,验证是否满足 5x+3y+z/3=100若y=33,则z=100-x-y,验证是否满足5x+3y+z/3=100 设x=1,若y=0,则z=100-x-y,验证是否满足5x+3y+z/3=100若y=1,则z=100-x-y,验证是否满足 5x+3y+z/3=100若y=33,则z=100-x-y,验证是否满足5x+3y+z/3=100 依次类推 设x=19,若y=0,则z=100-x-y,验证是否满足5x+3y+z/3=100若y=1,则z=100-x-y,验证是否满足5x+3y+z/3=100若y=33,则

30、z=100-x-y,验证是否满足5x+3y+z/3=100这是一种穷举算法(二重)。其基本思想是:对问题的所有可能状态一一测试,直到找到解或将全部可能状态都测试过为止。,程序如下:main() int x,y,z;x=0;while (x=19) y=0;while(y=33) z=100xy;if (5*x+3*y+z/3=100)printf(“%d,%d,%dn”,x,y,z);y=y+1;x=x+1;,循环控制有两种办法:计数法和标志法。 计数法是要先确定循环次数,然后逐次测试。完成测试次数后,循环结束。 标志法是达到某一目标后,使循环结束。,例8:打印出以下图案。 * * * * *

31、 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *,分析:找规律。 假设每一行的中心位置在第36列。“* ”之前的位置处补空格。 整个图形可分成上下两个部分:14行, 59行。 空格个数与行数之间的关系: (36n)14行:1:36-1 2:36-2 3:36-359行:由下向上 5:36-5 4:36-4 3:36-3 “*”个数与行数之间的关系: (2*n1)14行:1:1 2:3 3:559行:由下向上 5:9 4:7 3:5具体操作时,应该一行一行地打印。处理每一行时,先打印空格,再打印“*”

32、,最后换行。,程序如下: main( ) int i,j;for(i=1;i=1;i-) for(j=1;j=36-i;j+) printf(“ “);for(j=1;j=2*i-1;j+) printf(“*“);printf(“n“); ,例9:输入一个正整数,要求以相反的顺序输出该数。 例:输入12345,输出为54321。,main( ) int number;printf(“Input the number:”);scanf(“%d”,例10:猴子吃桃问题。猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾,又多吃了一个。第二天早上又将剩下的桃子吃掉一半,又多吃了一个。以后每天早上都吃

33、了前一天剩下的一半零一个。到第10天早上想再吃时,就只剩一个桃子了。求第一天共摘多少桃子。,main( ) int day,x1,x2;x2=1;for (day=9;day=1;day-) x1=(x2+1)*2;x2=x1;printf(“total=%dn”,x1);,例11:求100999之间的水仙花数。(水仙花数:指一个3位数,其各位数字的立方和等于该数, 如:153=13+53+33),main( ) int n,a,b,c; for (n=100;n=999;n+) a=n%10; /*个位*/b=n/10%10; /*十位*/c=n/100; /*百位*/if (a*a*a+b

34、*b*b+c*c*c= =n)printf(“%dt”,n); ,例12:爱因斯坦阶梯问题设有一阶梯,每步跨2阶,最后余1阶;每步跨3阶,最后余2阶;每步跨5阶,最后余4阶;每步跨6阶,最后余5阶;每步跨7阶时,正好到阶顶。问共有多少阶梯。,算法设计:设阶梯数为ladders,则条件可改写为: ladders%2=1 ladders%3=2 ladders%5=4 ladders%6=5 ladders%7=0,简化2:由条件知,阶梯数一定是奇数,故把上述数列中的数又去掉一半。于是可以对7,714,71414,(奇+奇=偶)用条件进行测试。,简化1:由条件知,阶梯数一定为7的整数倍。于是可以直

35、接从7开始,分别对7,14,21,28,数列进行测试。,程序如下: main( ) int ladders=7;while(ladders%3!=2|ladders%5!=4|ladders%6!=5)ladders+=14;printf(“flight of stairs = %dn“,ladders); 运行结果:flight of stairs = 119,main() int i=1,x=1;double e=1.0,y;for(y=1.0/x;y=1.0e-6;i+) x=x*i;y=1.0/x;e=e+y;printf(“e=%12.10lf“,e); ,作业: 1. 按下面的近似公式计算e的值:e=1+1/1!+1/2!+1/3!+1/n!+ 直到最后一项的绝对值小于106。,main() int i,year,f,f1,f2,f3;printf(“please enter year:“);scanf(“%d“, ,2. 递增的牛群:若一头小母牛,从第四个年头开始每年生一头母牛。按此规律,第n年时有多少头母牛?,main() int i,j,station,total=0;printf(“please input the stations numbers:“);scanf(“%d“, ,3. 准备客票:某铁路线上共10个车站,问需要准备几种客票?,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报