一、循环嵌套 二、图阵数阵 三、数域遍历
一、循环嵌套
顾名思义,就是一个循环体内存在着另一个循环 整体。
如:while ( )
{
for( )
{
…………
}
}
下面请看什么是“一次”?什么是“一遍”吧?
如:
for ( i=1; i<10; i++ )
for ( j=1 ; j<=10; j++ )
n++;
i=2,是外循环的一次循环,但内循环却要从J=1到10地运行10次,这就是一遍!!
1、如果把N++这条语句换成别的语句会是什么样呢?
2、又如果把for ( j=1; j<=10; j++ )换成for(j=1;j<=I;j++)又会是什么样?
例如:请判断下列程序输出结果
int a=0,b=0,k,j;
for(k=1;k<=10; k++)
{
a=a+1; b=0;
for (j=1; j<= 10; j++)
{
a=a+1 ; b=b+2;
}
}
printf("%d %d\n", a,b);
要我们判断a,b的值,关键是我们要知道a=a+1以及b=b+2的执行次数。而内循环中有a=a+1,外循环中也有a=a+1,但他们的执行次数是不同的;外循环中a=a+1只执行10次,也就是给a 加了10次1,而内循环中a=a+1却执行了100次,所以a=a+1共执行了110次,最终a 的值是110;由于b=0要执行10次也就是要清0十次,在前9次中,不管b的值是多少,第十次还是要清0的,所以我们只要从最后一次b为0开始,b=b+2只有最后10次执行的值才有效,故b的值最终是20。
再例如: int I,k,m,a=3;
for ( I=1 ;I<=5 ; i++){
a=a+3; ……… 执行5 次
for (k = 1 ; k<=6 ; k++){
a=a+3; …… 执行5*6 次
for(m = 1 ; m<= 7 ; m++){
a=a+3; …… 执行5*6*7 次
}}}
Printf(“%d”, a);
同上理a 的值应是738
请同学们自己分析下列程序段:
int h,j,k,n=0;
for(h=1; h<=10; h++ )
for (j =1 ;j<= h; j++)
for ( k=j ;k<=3; k++)
n = n + 1;
printf("%d", n);
程序的输出结果是 56
当然,循环嵌套不光是由FOR循环构成,while 和DO 都能构成循环嵌套。而由FOR构成的循环嵌套具有明确的循环次数,其它语句构成的循环嵌套虽然也有循环次数,但不是程序所关心的。
课堂练习:
1、计算1!+2!+3!+4!……+N!(N是一个从键盘输入的正整数)
2、编程打印如下图阵:
****
****
****
****
二、图阵与数阵
图阵与数阵即把某种字符或数字排成一个图形或一个方阵。这要求我们研究阵列中行与列的关系并灵活控制输出格式。虽然要求较高,但也有规律可循,下面我们结合实例一一剖析。
先请看一个简单的图阵:
①输出如下图阵
$
$ $
$ $ $
$ $ $ $
$ $ $ $ $
该阵有5行,第I 行有I列;
一般我们考虑用外层循环控制行数,内层循环控制列数,所以程序如下:
Int I,j;
for (I = 1;I <= 5 ;i++) ‘……图阵中有五行
for(j = 1; j<=I;j++) ‘……每行共有I列
printf(“$”);
printf(“\n”); ‘……换行
②输出如下图阵
&
& & &
& & & & &
& & & & & & &
此图阵较以上图阵,多出一个要求是:如何控制每一行第一个“&”的输出位置。可考虑如下方式:
For(I =1;i<=4;i++) {
For(k=1;k<=30-I;k++)Printf(“ ” );
‘…控制行首位置
For(j = 1; j<=2 * I–1 ; j++)
‘……第I行有2*I-1列
Printf(“&”);
Printf(“\n”);
}
由以上两例可知,第I行有多少列这个通项很重要。
③再如:输出如下星阵:
*
* * *
* * * * *
* * * * * * *
* * * * *
* * *
*
星阵有七行,那么第 I 行有多少列呢?不是解决这类问题的关键。
第 I 行有 7 – 2 * abs( 4 – I ) 列,所以该程序如下:
int i,k,j;
for(i =1; i<= 7; i++){
for (k=1;k<=(20+abs(4-i));k++)printf(" ");
for (j=1; j<=(7-abs(4-i)*2); j++) printf("*");
printf("\n");
④输出如下数字阵列
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
数阵与图阵不同,数阵的列有数值大小的问题而图阵则没有这个要求;故一般用数组先存储数值而后输出。由于本例较简单,可直接输出,如何用数组这种形式输出该阵请同学们在学完数组一章后自己考虑 。
程序如下:
int i,k,j;
for(i=1;i<=5;i++){
for(j=1;j<=i;j++)
注意输出的数值大小与两个循环变量之间的关系
printf("%d",j);
printf("\n");}
请再看看如下数阵:
1
1 2 1
1 2 3 2 1
1 2 3 4 3 2 1
1 2 3 4 5 4 3 2 1
同以上星阵,也得控制输出位置;有五行,第I行有2*I-1列,且输出项是两头小,中间大的数值形式,变化很有规律。
For (i=1;i<=5;i++){
For(k=1;k<=30-I;k++)printf(“ ”);
For(j=1;j<=2*i-1;j++)
Printf(“%d”,5-abs(i-5));
Printf(“\n”);
能输出:
1
2 2 2
3 3 3 3 3
4 4 4 4 4 4 4
5 5 5 5 5 5 5 5 5
为什么呢?
因为输出项表达式一定与变量J有关,象5-abs(i-5)这样一定不行。只要把输出项表达式换成i-abs(i-j)就行了!
好的,再来看看如下数阵:
1
1 2 1
1 2 3 2 1
1 2 3 4 3 2 1
1 2 3 4 5 4 3 2 1
1 2 3 4 3 2 1
1 2 3 2 1
1 2 1
1
几乎是以上两个数阵的对称合并。
我们先把上述程序控制行的外层循环换成:
for (i=1;i<=9;i++){,控制输出位置的循环换成:for(k=1;k<=30+abs(i-5);k++)printf(" ");
控制输出个数的内层循环写成:for(j=1;j<=9-2*abs(i-5);j++)
输出项表达式不变就能得到:如下数字阵列:
1
1 2 1
1 2 3 2 1
1 2 3 4 3 2 1
1 2 3 4 5 4 3 2 1
1 2 3 4 5 6 5
1 2 3 4 5
1 2 3
1
当然这不是我们所要的数阵了!右上角的数字没有跟上变化!
大家思考一下:我们可以把Printf(“%d”,5-abs(i-5))中的I用5-abs(i-5)替换就行了!所以以上数阵的程序如下:
{int i,k,j;
for (i=1;i<=9;i++){
for(k=1;k<=30+abs(i-5);k++)printf(" ");
for(j=1;j<=9-2*abs(i-5);j++)
printf("%d",(5-abs(i-5))-abs(5-abs(i-5)-j));
printf("\n");
}
}
三、数域的遍历
1、顾名思义是对某个范围中所有数,从头到尾经过一遍,查找符合条件的数。
例如:求1到100以内不能被3整除的整数的个数。
分析:1-100 就是一个数域,每个数都验一遍,能被3整除的就记录下来,即:
For(I = 1;i<=100;i++){
if (I % 3 == 0) continue; n = n + 1;}
printf(“%d”,n);
一般地对某个数域进行查找,可考虑使用FOR循环,然后对循环变量进行条件测试。如古典数学问题:
百钱百鸡
百马百担(请同学们自己动手解决)
再例:求1+3+5+……99的值
该题要求把这个数域中的所有数累加起来,程序如下:
for (I = 1;i<=100;i++ )s=s+I;
则结果的值在S中。
类似的题目如下:(同学们自己动手)
求 1*2*3*4*……99的值
求 1+1/2+1/3+……+1/1000的值 求 1-1/2+1/3-……-1/1000的值
2、另一例数域的遍历,是不清楚这列数每个数的具体大小,但也可以根据初值和相邻两数的关系,一个挨一个地计算出这列数的每个数。
例如:山中有一堆核桃,小猴子看到后吃了一半,觉得不过瘾又多吃了一个,第二天又把剩下的核桃吃了一半,又多吃了一个,按这种吃法,到了第十一天只剩下一只核桃,问这堆核桃共有多少个?
这个问题与以上问题不同的是,只知道结果求最初的值,但我们不难想到,相邻两天的核桃数有如下关系:Xn = (Xn + 1 + 1 )* 2, 也就是说,X1,X2,X3,……X11=1,这列数有如上关系,我们只要知道初值就能很容易地推导出第二个值、第三个值……。因此对于这类问题,我们只需要把握初值,通过一次又一次的代入关系式就能得到第二个值,第三个值……。
那么程序如下:
Int i,t = 1;
For(i = 1;i<=10;i++)t =(t+1) * 2;
Printf(“这堆核桃共有%d个”,t);
这类问题,我们归纳为数列问题。尽管也是对这列数的遍历,但是与前述不同的是这列数不是已知的,需要我们逐次求出。再看一例:
一球从100米高度自由落下,每次落地反跳回原高度的一半再落下,求它在第十次下落时共经过多少米?第十次反弹多高?
分析:已知数据的第一项,且相邻两数据项的关系是1/2,另外,注意球是先落下后弹起。解:
解:
Int I,h = 100, s = 100;
for (I =1;i<=9;i++){h = h / 2; s = s + 2 * h}
printf 略 s , h /2 ……第九次下落的高度的一半即第十次反弹高度