470 likes | 676 Views
第 5 章、循环程序设计. 主讲教师:陈荣钦 QQ : 241881888. 本章概要. 为什么需要循环 while 结构 do…while 结构 for 结构 循环嵌套 break 和 continue 语句. 为什么要循环. 问题:统计 n 个学生的平时成绩, n 根据输入而定。如样例: 5 50 60 70 80 90 10 60 70 80 90 100 100 90 80 70 60 解决思路:重复输入成绩 n 次,求和后将其除以 n 。. 循环结构擅长处理这种大量重复的操作. while. F. 表达式. T. 循环体.
E N D
第5章、循环程序设计 主讲教师:陈荣钦 QQ:241881888
本章概要 • 为什么需要循环 • while结构 • do…while结构 • for结构 • 循环嵌套 • break和continue语句
为什么要循环 • 问题:统计n个学生的平时成绩,n根据输入而定。如样例: • 5 • 50 60 70 80 90 • 10 • 60 70 80 90 100 100 90 80 70 60 • 解决思路:重复输入成绩n次,求和后将其除以n。 循环结构擅长处理这种大量重复的操作
while F 表达式 T 循环体 while结构 • 执行流程: • 一般形式: while (表达式) { 任何语句1; 任何语句2; …… } 若表达式非0,则执行循环体各语句,重复以上过程直到表达式为0时结束循环
循环变量i初值为1 s初值为0 循环成立条件 循环变量i增值 用while语句求1~100的累计和 1初始化、2判断条件、3执行循环改变控制变量 #include <stdio.h> int main ( ) { int i = 1, s = 0; while(i<=100) { s += i; i++; } //循环结束后输出 printf ("sum = %d\n", s); } 运行结果: sum = 5050
表达式的值一开始就为false,循环体则一次也不执行表达式的值一开始就为false,循环体则一次也不执行 int a = 0, b = 0; while (a > 0) b++; int i = 1, s; while(i<=100) { s+= i; i++; } printf ("%d\n", s); } 相关的变量一定要赋初值,否则结果可能未预知 结果:-858988410 while语句注意事项
int i = 1, s=0; while(i<=100) { s += i; //i++; } printf ("sum = %d\n", s); } 循环控制变量一般需要在循环体内改变,否则可能死循环 while语句注意事项
TOJ 1461 求平均值 题目描述: 求n个数的平均数。 输入: 输入数据有2行,第一行为n,第二行是n个数。 输出: 输出n个数中的平均数,结果保留小数点2位。 样例输入: 5 -1 2.1 3 4 -5.8 样例输出: 0.46
参考代码 注意循环控制变量从 n最后减到0,因此使用临时变量n1来控制。
TOJ 1179 最小公倍数与最大公约数 题目描述: 求这两个正整数的最小公倍数和最大公约数。 输入: 输入包括一行。两个以空格分开的正整数。 输出: 两个整数的最小公倍数和最大公约数。 样例输入: 6 8 样例输出: 24 2
题目分析 • 两个数m和n的最大公约数是既能被m整除,又能被n整除的所有数中的最大值。 • 逐个数检验能否被整除?效率太低! • 使用辗转相除法(又名:欧几里德算法 )
辗转相除法思想 • gcd(a, b) 表示a和b的最大公约数,设r = a mod b,则gcd(a,b)=gcd(b,r) • 证明(自学): • 令c=gcd(a, b),则设a=mc,b=nc • 因为r =a-kb=mc-knc=(m-kn)c,因此c也是r的约数。即c是b和r的公约数 • 另外n和m-kn是互素的,否则,可设m-kn=xd,n=yd,(d>1),则m=kn+xd=kyd+xd=(ky+x)d,则a=mc=(ky+x)dc,b=nc=ycd,故a与b最大公约数成为cd,而非c,与前面结论矛盾
求最小公倍数 • m和n的最小公倍数=m*n/最大公约数 • 说明: • 设m和n的最大公约数为c,则m=a1*c, n=b1*c;因为c为最大公约数,所以a1、b1互质。因此m和n的最小公倍数为a1*c*b1=(m/c)*c*(n/c)=m*n/c。
算法设计 • (1)输入m和n。设p = m*n。 • (2)设r为m除以n的余数,若r等于0,则n是最大公约数,转(4),否则转(3) • (3)把n赋给m,把r赋给n,转(2)。 • (4)计算最小公倍数为p/n。
do 循环体 while T expr F do…while结构 • 一般形式: • 执行流程: do { 任何语句1; 任何语句2; …… } while(表达式); 特点:先执行循环体,再判断表达式,注意最后有分号。
使用do…while求解TOJ1179 注意m才是最大公约数,因为n的值最后赋给了m。而r和n循环结束后均为0
for expr1 F expr2 T 循环体 expr3 • 执行流程: for结构 • 一般形式: for (表达式1;表达式2;表达式3) { 任何语句1; 任何语句2; …… } for结构更好的表达了循环结构: (1)表达式1:初始化(2)表达式2:循环条件(3)表达式3:改变控制变量
用for语句求1至100的和。 #include <stdio.h> int main() { int i , s = 0; for (i = 1; i <= 100; i++) s += i; printf ("sum = %d\n", s); } 运行过程: (1)初始化:i=1 (2)1<=100成立,因此执行s += 1得s=1 (3)i++后得i=2 (4)2<=100成立,因此执行s += 2得s=3 (5)i++后得i=3 …一直到i=101后结束循环。 运行结果: sum = 5050
for语句注意事项 三个表达式可以为任何语句,如可以为逗号表达式 例:计算1*2+3*4+5*6+…+99*100。 int i, j; int sum = 0; for ( i =1, j = 2; i <= 99; i = i + 2, j = j + 2 ) sum += i *j; printf ("sum = %d\n", sum); 逗号表达式 逗号表达式
for语句注意事项 根据实际需要,可以省略任何一个表达式,甚至全部省略,但分号不能省略 #include <stdio.h> int main ( ) { int i, s= 0; i = 1; for ( ; i <= 100; i++) s += i; printf("sum = %d\n", s); } for ( ; i <= 100; ) { • s += i; • i++; }
for语句注意事项 表达式2如果为空则相当于值为真,即始终成立。 死循环! for (a = 1; ; a++) printf ("%d\n", a); 循环体可以是空语句。 结果:101 for (a = 1; a<=100; a++); printf ("%d\n", a);
1167 分数序列 题目描述: 有一个分数序列:2/1, 3/2, 5/3, 8/5, 13/8, …编写程序求出这个序列的前n项之和。 输入: 输入只有一个正整数n,1≤n≤10。 输出: 输出改序列前n项和,结果保留小数后6位。 样例输入: 3 样例输出: 5.166667
题目分析 • 2/1, 3/2, 5/3, 8/5, 13/8 • 递推规律: • 第一项分子A1=2,分母B1=1 • Ai+1 = Ai + Bi,Bi+1 = Ai for(i=0,s=0,a=2,b=1;i<n;i++){ s = s + a/b;//累加当前项 t = a + b; //临时存储Ai+1 b = a; //Bi+1 a = t; //Ai+1 }
1477 余弦 题目描述: 输入n的值,计算cos(x)。 输入: 输入数据有一行,包括x和n。第一数据为x(x<10),第二个数据为n(n<=10000) 输出: 输出cos(x)的值,保留4位小数 样例输入: 0.0 100 样例输出: 1.0000
题目分析 • 注意通项的分子分母可能很大,因此不能分开计算; • 递推规律 • A1 = 1
练习 • 1468 求级数值 • 1476 求圆周率 • 1455 数字串求和
外循环 • for( ; ;) • { …… • do • { …… • }while(); • …… • while() • { …… • } • …... • } 内循环 内循环 循环嵌套 三种循环可互相嵌套,层数不限 1. 外循环每执行一次,内循环都要从头执行一遍。 2. 并列的两个内循环,先执行完前面的,再执行后面的。
1 3 9 1 2 2 6 2 4 18 27 3 3 9 6 8 36 4 4 12 5 10 15 5 45 6 54 12 18 6 63 21 14 7 7 72 8 16 24 8 27 9 9 81 18 j i …………….. 输出九九表
参考代码 #include <stdio.h> int main() { int i, j; for (i = 1; i < 10; i++) printf ("%3d", i); printf ("\n---------------------------\n"); for (i = 1; i < 10; i++) for (j = 1; j < 10; j++) printf(j==9?"%3d\n":"%3d",i * j); }
i=1 假(0) i<10 真(非0) j=1 假(0) j<10 真(非0) printf 外循环 j++ 内循环 i++ 嵌套循环分析 for(i=1;i<10;i++) for(j=1;j<10;j++) printf;
1172 打印菱形 题目描述: 从键盘输入一个整数n(1≤n≤9),打印出指定的菱形。输入: 正整数n(1≤n≤9)。 输出: 指定的菱形。 第一行前面有n-1个空格,第二行有n-2个空格,以此类推。 样例输入: 5 样例输出:
问题分析 • 两重循环: • 外循环共有2*n-1遍(即行数) • 内循环有两个: • 一个用于输出空格,一个用于输出* • 分上半部分和下半部分讨论循环的次数 • 上下两半通过外循环的控制变量来区分,若i<=n (第一行为i=1),则上半部分,否则为下半部分
break语句 • 在循环或switch语句中,终止并跳出循环体或开关体 • 任何其它语句不能使用。 • break只能终止并跳出最近一层的结构。 while (表达式1) {… … if (表达式2) break; … … } 语句…… do {… … if (表达式2) break; … … } while (表达式1); 语句…… for (; 表达式1; ) {…… if (表达式2) break; …… } 语句……
运行结果: howareyou↙ HOWAREYOU break举例 输入小写字母转换成大写字母,直到输入非小写字母字符 #include <stdio.h> int main(){ char c; while(1){ c = getchar(); if (c>='a' && c<='z') putchar(c-32); else break; } } #include <stdio.h> int main() { char c; while(c = getchar(),c>='a' && c<='z') { putchar(c-32); } }
break如何跳出多重循环 int tag = 0; for (…) { while (…) { …… if (…) { tag = 1; break; } …… } if ( tag ) break; …… } for循环后的第一条语句 for (…) { while (…) { …… if (…) break; … } while循环后的第一条语句 } 方法:定义一个变量tag,在每层循环后加语句:if (tag) break;其值为1表示跳出循环体,为0则不跳出。
goto语句跳出嵌套循环 for (…) { while (…) { …… if (…) { goto Label1; } …… } } Label1: for循环后的第一条语句 语法: goto 标签名 …… 标签名: …… 建议: 除了跳出嵌套循环,建议不要使用goto语句。
continue语句 结束本次循环,进行下一次是否执行循环体的判断。 for (…){ while (…){ …… if (…) continue; …… } while循环后的第一条语句 }
求输入的十个整数中正数的个数及其和。 #include <stdio.h> int main(){ int i, a, num = 0; double sum = 0; for(i=0; i<10; i++){ scanf ("%d", &a); if (a <= 0) continue; num++; sum += a; } printf ("num=%d, sum=%.2f\n", num, sum); } 运行结果: num=8, sum=45 假设输入的10个整数为:1 2 3 –4 5 –6 7 8 9 10
exit( )函数 • 功能: 终止整个程序的执行,强制返回操作系统。 • 调用形式: void exit( int status ); 头文件<stdlib.h> • 说明: 参数status为int型,当status的值为0或为宏常量EXIT_SUCCESS时,表示程序正常退出;当status的值为非0或为宏常量EXIT_FAILURE时,表示程序出现某种错误后退出。
循环结构类型的选择原则 • 循环次数在执行循环体之前能够确定,一般用for循环; • 若循环体至少执行一次用do…while循环 • 各种循环结构是可以互相转换的,因此没有强制性原则。
TOJ4589: 素数判断 题目描述: 给定一个大于1的正整数,判断是否为素数。 输入: 输入数据有多组,每组占一行,每行一个正整数n(1<n<10000)。输入以EOF结束。 输出: 若为素数,输出Yes,否则输出No。 样例输入: 3 4 样例输出: Yes No
问题分析 • 素数是指除了能被1和它本身整除外,不能被其它任何整数整除的数。 • 因此只要循环判断i=2~n-1,检查n能否被i整除,只要存在一个能整除的,n就不是素数。 • 事实上能够证明只要判断i=2~ 即可。
算法 从键盘输入一正整数n。 (1)计算t = (2)i从2到t,依次检查m除以i的余数是否为0,若为0,则判定n不是素数,结束循环;否则继续下一次循环直到全部检验完毕为止; (3)循环结束后,若i<=t,说明循环是被强制结束的,n不是素数。否则n是素数。
练习 • 1177 打印数字图形 • 1478 打印金字塔 • 1428 空心三角形