第4章 循环控制.docx
- 文档编号:26173452
- 上传时间:2023-06-17
- 格式:DOCX
- 页数:23
- 大小:68.37KB
第4章 循环控制.docx
《第4章 循环控制.docx》由会员分享,可在线阅读,更多相关《第4章 循环控制.docx(23页珍藏版)》请在冰豆网上搜索。
第4章循环控制
第4章循环结构程序设计
一、概述
循环(或称重复)是计算机解题的—个重要特征。
计算机运算速度快,最宜于用于重复性的工作;在程序设计时,人们也总是把复杂的、不易理解的、难于求解的问题,转换为易于理解的、多次重复的操作。
这样,一方面可以降低问题的复杂性,减低程序设计的难度,减少程序书写及输入的工作量;另一方面可以充分发挥计算机运算速度快、能自动执行程序的优势。
C的循环控制一般由4部分组成:
循环初值语句、循环条件、循环主体语句和循环变量增值语句,执行的过程有两种形式:
循环初值语句循环初值语句
Y循环条件N循环主体语句
循环变量增值语句
循环主体语句
循环变量增值语句Y循环条件N
例用四种不同的循环语句求1+2+3+…+100
二、用goto语句构成循环
goto语句的格式:
goto标号;开始
main(){
inti=1,sum=0;i=1,sum=0;
loop:
if(i<=100)
{sum=sum+i;Yi<=100N
i=i+i;
gotoloop;}sum=sum+i;
printf("%d\n",sum);i=i+1;输出sum
}
结束
三、while语句
main(){
inti=1,sum=0;
while(i<=100)
{sum=sum+i;
i++;}
printf("%d\n",sum);
}
四、do-while语句
main(){开始
inti=1,sum=0;
do{i=1,sum=0
sum=sum+i;
i++;sum=sum+i;
}while(i<=100);i++;
printf("%d\n",sum);
}i<=100
五、for语句输出sum
main(){
inti,sum=0;结束
for(i=1;i<=100;i++)
sum+=i;
printf("%d\n",sum);
}
练习:
修改程序,使之计算
(1)2+4+6+…+100
(2)1+3+5+…+99
(3)1×2×3×…×20
六、循环的嵌套
例:
求e≈1+1/1!
+1/2!
+1/3!
+…+1/20!
算法1:
main(){
inti,j,p;
floatsum=1.0;
for(i=1;i<=20;i++)
{p=1;
for(j=1;j<=i;j++)
p=p*j;
sum=sum+1.0/p;
}
printf("%f\n",sum);
}
算法2:
利用n!
=(n-1)!
n特点,可以将算法改进成不用循环嵌套。
main(){
inti,j,p=1;
floatsum=1.0;
for(i=1;i<=20;i++)
{p=p*i;
sum=sum+1.0/p;
}
printf("%f\n",sum);
}
七、几种循环的比较
1、四种循环的一般形式
循环初值语句;循环初值语句;
loop:
if(循环条件)do{
{循环主体语句;循环主体语句;
循环变量增值语句;循环变量增值语句;
gotoloop;}}while(循环条件);
循环初值语句;
while(循环条件){
循环主体语句;
循环变量增值语句;}
for(循环初值语句;循环条件;循环变量增值语句)
循环主体语句;
2、几种循环的比较
(1)四种循环都可以处理同一问题,一般可以相互替代;
(2)while和do~while循环在循环体内应该含有使循环趋于结束的语句(如i++等等)。
for循环将循环初值语句、循环条件、循环变量增值语句放在括号内,甚至还可以将主体语句也放在“循环变量增值语句”处。
(3)while和do~while循环在循环体外应该含有循环初值语句。
(4)while、do~while和for循环可以用break提前结束循环,用
continue结束本次循环。
八、break语句和continue语句
break的作用有两种:
一是从switch流程中跳出,另一是从循环语句中跳出;
continue的作用是结束本次循环,即跳出循环体下面尚未执行的语句,接着进行下一次是否执行循环的判定。
例6.5把100~200之间的不能被3整除的数输出。
算法1:
main(){
intn;
for(n=100;n<=200;n++)
{if(n%3==0)
continue;
printf("%d",n);
}
}
算法2:
main(){
intn;
for(n=100;n<=200;n++)
if(n%3!
=0)
printf("%d",n);
}
九、程序举例
当一个问题要应用循环语句来处理时,关键就是找出循环的四要素:
循环初值语句、循环条件、循环主体语句和循环变量增值语句(循环变量人们通常用i,j,k,l,m,n等表示)。
例6.6用
公式求π的近似值,直到最后一项的绝对值小于10-6为止。
算法分析:
循环初值语句——i=1;p=0,s=1;
循环条件——1/n>=10-6;
循环主体语句——p=p+s/n;s=-s;
循环变量增值语句——n=n+2;
例6.7兔子繁殖问题。
著名意大利数学家Fibonacci曾提出一个有趣的问题:
设有一对新生兔子,从第三个月开始它们每个月都生一对兔子。
按此规律,假设没有兔子死亡,问每个月共有多少对兔子。
显然,每月的兔子数组成如下数列:
1,1,2,3,5,8,13,21,34,……
并把它称为Fibonacci数列。
上述算法可以描述为
f1=f2=1
(1)
fn=fn-1+fn-2(n>=3)
(2)
式
(2)称为迭代公式,式
(1)为其初值。
算法分析:
(假设只求前40月每月兔子总数)
循环初值语句——f1=f2=1;printf(f1,f2);i=3;
循环条件——i<=40
循环主体语句——f=f1+f2;printf(f);fl=f2;f2=f;
循环变量增值语句——i++;
main()
{longintf,f1=1,f2=1;
inti;
printf("%12ld%12ld",f1,f2);
for(i=3;i<=40;i++)
{f=f1+f2;
printf("%12ld",f);
f1=f2;f2=f;
}}课本P117(略)。
例6.8判断素数问题——输出1~1000之间的所有素数。
(例2.22)
算法分析:
循环初值语句——n=2;
循环条件——n<=1000;
循环主体语句——用2~
去除n,从而判断n是否为素数,若是,则输出n;
循环变量增值语句——n=n+1;
#include
main()
{inti,k,n;
for(n=2;n<=1000;n++)//逐个取出整数来判断
{k=0;//“曾被整除”为假
for(i=2;i if(n%i==0){k=1;break;}//“曾被整除”为真,退出fori if(k==0)printf(“%d”,n);//“曾被整除”为假则输出n } } 例6.10译密码问题 将输入的一行字母变成其后的第4个字母(循环),其它字符不变。 算法分析: 循环初值语句——(空) 循环变量增值语句——(空) 循环条件——(输入的字符变量c不是回车键); 循环主体语句——如果c不是字母,printf(c);不然 c=c+4;若现在c仍是字母则printf(c);不然printf(c-26); main() {charc; while((c=getchar())! ='\n'){ if((c>='a'&&c<='z')||(c>='A'&&c<='Z')) {c=c+4; if(c>'Z'&&c<'Z'+4||c>'z')c=c-26; } printf("%c",c); }} 例1打印九九表(如下图)。 123456789 123456789 24681012141618 369121518212427 4812162024283236 51015202530354045 61218243036424854 71421283542495663 81624324048566472 91827364554637281 算法分析: 分三部分 s1: 打印表头,用for(i=1;i<=9;i++)printf("%4d",i); s2: 打印隔线,用for(i=1;i<=36;i++)printf("%c",'-'); s3: 打印表体,用双重循环for(i=1;i<=9;i++) for(j=1;j<=9;j++) printf("%4d",i*j); main() {inti,j; for(i=1;i<=9;i++) printf("%4d",i); printf("\n"); for(i=1;i<=36;i++) printf("%c",'-'); printf("\n"); for(i=1;i<=9;i++) {for(j=1;j<=9;j++) printf("%4d",i*j); printf("\n"); } } 例2搬砖问题。 36块砖,36人搬;男搬4;女搬3,两个小孩抬一砖。 要求一次全搬完,问男、女、小孩各若干? 分析: 男人(men)的可能取值范围为: 0~8; 女人(women)的可能取值范围为: 0~l2; 小孩(children)的可能取值范围为: 0~36; 采用穷举法,首先考虑men分别取0~8中的各个值时,找符合题意的women,children。 main() {intmen,women,children; for(men=0;men<=8;men++) for(women=0;women<=12;women++) {children=36-women-men; if(4.0*men+3.0*women+children/2.0==36.0) {printf("\nmenis%d",men); printf("\twomenis%d",women); printf("\tchildrenis%d\n",children);} }} 类似的百钱买百鸡问题: 鸡翁一值钱五,鸡母一值钱三,鸡雏三值钱一。 百钱买百鸡,问鸡翁鸡母鸡雏各几何? 例3求两个非负整数u和v的最大公因子(即最大公约数)。 算法分析: 求两个非负整数的最大公因子的方法可用辗转相除法。 其算法可以描述为 当v不为0时,辗转用操作: r=u%v,u=v,v=r 消去相同的因子。 直到v=0时,u的值即为所求的解。 main() {intu,v,r; printf("pleaseenter2integers: "); scanf("%d,%d",&u,&v); while(v! =0) {r=u%v; u=v; v=r;} printf("%d\n",u); } 例4爱因斯坦的阶梯问题。 设有一阶梯,每步跨2阶,最后余1阶;每步跨3阶,最后余2阶;每步跨5阶,最后余4阶;每步跨6阶,最后余5阶;每步跨7阶时,正好到阶梯顶。 问阶梯最小共有多少阶。 算法分析: 设阶梯数为s,则题中条件可以改写为: ①s%2=1 ②s%3=2 ③s%5=4 ④s&6=5 ⑤s%7=0 由条件⑤知,阶梯数—定为7的整数倍。 于是可以从7开始,分别对7,14,21,28,…数列进行测试,看哪一个符合题意。 而由条件①知,阶梯数一定是奇数,故可把上述数列中的数去掉一半。 于是可以得到这样一个算法: 依次对7,7+14,7+14+14,…用条件②、③,④进行测试,找出符合题意者。 由此算法写出下面的程序: main() { ints=7; while(s%3! =2||s%5! =4||s%6! =5) s+=14; printf("%d\n",s); } 一元方程的迭代解法。 一元方程f(x)=0,反映了科学技术领域内的一类常见的规律。 很多人总习惯于设法构造解析表达式去精确地描述一个方程的解。 但是,能用解析表达式精确地描述出解的方程实是太有限了。 业已证明,一元五次以上的方程找不出通用的根的解析表达式。 在这种情况下,人们不得不求助于一些近似解法。 一种粗略的方法是画出函数的曲线,从曲线上估计方程的粗略解。 还有一种方法是用迭代法使方程的根不断地精确化。 用迭代法求一元方程f(x)=0的解,就是要把方程f(x)=0,改写为一种迭代形式: xn+1=φ(xn) 选取适当的初值x0(粗略的解),便可以通过重复迭代构造出一个序列: x0,x1,x2,……xn,…… 若这个数列收敛,即存在极限,且函数连续(在所求解的区间),则很容易很到: 这个极限值x*就是方程f(x)=0的一个解。 当然,我们不可能重复无穷多次。 一般说来重复的次数应由指定的精确度(或误差)决定。 当误差小于给定值ε时,便认为所得到的解足够精确了,迭代过程可以结束。 所以,这种用迭代法解一元方程根的重复结构都是用误差进行控制的。 即每迭代一次要对所得到的误差作一次判断,看其是否已小于给定的误差要求。 当然,不可能采用绝对误差|xn-x*|<ε,因为知道了绝对误差,就知道了根的精确值x*,也就无须再计算了。 通常是用当前的近似解与上次的近似解之差作为相对误差进行判断的,即当|xn-xn-1|<ε时,取xn为x*的近似解。 解一元方程的迭代方法很多,下面介绍两种有代表性的方法: (1)二分迭代法 二分迭代法的思想如图3.23所示。 先取f(x)=0的两个粗略解x1与x2。 若f(x1)与 f(x2)符号相反,则方程f(x)=0在区间(x1,x2)中至少有一个根。 若f(x)在区间(xl,x2)内单调(单调升或单调降),则f(x)=0之间应有一个实根。 取 x3=(x1+x2)/2 并在x1与x2中舍去函数值与f(x3)同号者(图中为x2,因为f(x2)与f(x3)同符号),x3与剩下的一个粗略解(图中为x1)组成一个新的小的含根区间。 x1x4x3x2 再取(x1,x3)的中点x4,若f(x1)与f(x4)同符号,则得到更小的含根的区间(x3,x4)。 如此重复,便可以构造出一个序列: x1,x2,x3,……,xn-1,xn,…… 当xn与xn-1之差小于给定的误差ε0时,便得到所求得近似解。 (2)牛顿迭代法 求函数f(x)=0在x0附近的根。 迭代法公式(推导过程见高等数学课本,略): 例5用牛顿迭代法计算一个正实数的平方根。 算法设计: 建立迭代关系式。 由题意可以写出: 或x2=a 于是得到方程: 代入牛顿迭代公式,得: xn+1=(xn+a/xn)*0.5 这就是要建立的迭代关系式。 (1)初值——可设初值为a(当然也可以为其它值) (2)循环主体——x2=(x1+a/x1)*0.5;e=x2-x1;x1=x2; (3)循环条件——|e|≥EO。 (4)循环变量增值语句——(空) #include"math.h" #defineE00.000001 main() {floatx1,x2,e,a; printf("inputa: "); scanf("%f",&a); x1=a; do{ x2=(x1+a/x1)*0.5; e=x2-x1; x1=x2; }while(fabs(e)>=E0); printf("\nThesquarerootof%.2fis%.6f\n",a,x2); } 习题解 1求两个正整数的最大公约数和最小公倍数 main() {intm,n,x,y,t; printf("请输入两个正整数: "); scanf("%d,%d",&m,&n); x=m;y=n;//保留原数 while(m%n! =0){t=m;m=n;n=t%n;}//辗转相除法 printf("整数%d和%d的最大公约数和最小公倍数分别为: %d,%d\n",x,y,n,x*y/n); } 2统计所输入的一行字符中字符、数码、空格和其它字符的个数 main() {charc; intletter=0,space=0,digit=0,other=0; printf("scanfcharacterstring: \n"); while((c=getchar())! ='\n')//输入一行字符,并对每个字符逐个检查处理 { if(c>='a'&&c<='z'||c>'A'&&c<='Z') letter++; elseif(c=='') space++; elseif(c>='0'&&c<='9') digit++; elseother++; } printf("letter=%d,space=%d,digit=%d,other=%d\n", letter,space,digit,other); } 3给定两个数字,比如2和6,求2+22+222+2222+22222+222222的值。 main() {inta,n,i=1,sn=0,tn=0; printf("value(a,n)\n"); scanf("%d,%d",&a,&n); //简单些: for(i=1;i<=n;i++) {tn=tn*10+a; sn=sn+tn;} while(i<=n) {tn=tn+a; sn=sn+tn; a=a*10; ++i;} printf("a+aa+aaa+....=%d\n",sn); } 4求值1! +2! +3! +...+20! main() {inti; doublesum=0,s=1; for(i=1;i<20;i++) {s=s*i; sum=sum+s; } printf("1! +2! +3! +...+20! =%20.0f\n",sum); } 5求值 main() { inti; floats1=0,s2=0,s3=0,sum=0; for(i=1;i<=100;i++) {s1=s1+i; if(i<=50)s2=s2+i*i; if(i<=10)s3=s3+1/i; } for(i=1;i<=100;i++) s1=s1+i; for(i=1;i<=50;i++) s2=s2+i*i; for(i=1;i<=10;i++) s3=s3+1/i; sum=s1+s2+s3; printf("sum=%f\n",sum); } 6求“水仙花”数: 一个3位数,其各位数字的立方和恰好等于该数本身。 例如,153是一个水仙花数,因为13+53+53=153. main() {inti; floata,b,c,d; for(i=100;i<1000;i++) {a=i/100;//求百位数字 b=i/10-a*10;//求十位数字 c=i%10;//求个位数字 if(i==a*a*a+b*b*b+c*c*c)printf("%d",i); } printf("\n"); } 7求1000内所有的“完全数”: 一个数所有因子之和恰好等于其自身。 例如,6是一个完全数: 6=1+2+3. #include main() {inti,j,n,s,k; for(n=2;n<1000;n++)//从2~1000逐个判别是否为“完全数” {s=1;k=sqrt(n); for(i=2;i if(n%i==0)s=s+i+n/i;//若i是n的因子,则n/i也是 if(n==s)printf("%d",n);//若是“完全数”则输出之 } } 8求下列数列前20项之和 main() {inti,f1=1,f2=2; floats=0.0; for(i=1;i<=20;i++) {s=s+(float)f2/f1; f2=f1+f2; f1=f2-f1; } printf("%f\n",s); } 9一球从100m高度自由落下,每次落地后反弹到原高度的一半,再落下,在反弹。 求它在第10次落地时,共经过了多少米? 第10次反弹多高? main() {inti; floats=10.0,t=10.0; for(i=2;i<=10;i++) {t=t/2.0; s=s+2*t; } printf("%f,%f\n",s,t); } 10猴子吃桃子问题。 猴子第一天摘了若干桃子,当即吃了一半,还不够瘾,又多吃了一个。 第二天又将剩下的桃子吃掉一半,又多吃了一个。 以后每天都吃了前一天剩下的一半零一个。 到第10天想在吃时,就只剩下1个桃子了。 求第一天共摘了多少桃子。 main() {intn=1,i; for(i=9;i>0;i--)n=(n+1)*2; printf("num=%d\n",n);} 11用迭代法求 .(可用迭代公式求a的平方根: xn+1=(xn+a/xn)/2) #include"math.h" #defineE01e-5 main() {floatx1,x2,e,a; printf("inputa: "); scanf("%f",&a); x1=a; do{ x2=(x1+a/x1)*0.5; e=x2-x1; x1=x2; }while(fabs(e)>=E0); printf("\nThesquarerootof%.2fis%.6f\n",a,x2); } 12用牛顿迭代法求下列方程的根。 2x3-4x2+3x-6=0 #include main() { floatx,x0,f,f1; x=1.5; do
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第4章 循环控制 循环 控制