【程序设计】3.3 [做循环] 条件循环

 

3.3 条件循环

for n 和 for a,b 都是确定次数的循环,但有时候我们不知道要循环多少次。要当某个条件成立(或者不成立)时才结束循环,之前一直重复执行循环体。这种循环称为条件循环

事实上,for n 和 for a,b 也可以理解为这样的循环,即当循环变量超过 n 和 b(超过不一定是指大于)时就结束循环。条件循环是更一般的循环形式。

计算两个数的最大公约数,有个经典的方法叫辗转相除法。两个正整数 a 和 b,假设 a>b,则用 a 除以 b 的余数替代 a,现在 a<b 了,再用 b 除以 a 的余数替代 b,然后又有 a>b 了,…,如些反复,直到 a 和 b 中有一个是 0 了,则另一个还不是 0 的就是最初的 a 和 b 的最大公约数。因为 a,b 反复交换地位计算余数,所以叫辗转相除法。

这是二千多年前古希腊几何学家欧几里得发明的办法,有兴趣的读者可以自己证明,我们这里用程序代码来实现它。

设原始的两个数放在 A1 和 B1 格中。


A

B

1

7215

2345

2

for B1>0

=A1%B1

3


>A1=B1

4


>B1=B2

计算结果将会在 A1 中。

A2 格的代码 for B1>0,for 后面跟了一个计算结果是布尔值的计算表达式,当它计算出 true 时,循环体将被执行一次,然后回到 A2,再次计算这个布尔表达式,如果还是 true 则再执行循环体,…;直到某次计算这个布尔表达式为 false 时,循环中止。

这个逻辑就能实现欧几里得的辗转相除法。我们不知道要循环多少次,只知道当 B1 为 0 时循环就可以终止了。

大多数程序语言都有条件循环,但一般会使用 while 来表示。

类似 if,else,for 这样的单词,将在程序代码中用来表示某些特殊语句,称为程序语言的保留字或者关键字。这些保留字都有特别的意义,不能再被用作变量名等标识符。所有程序语言都会有一批自己的保留字。

SPL 不希望有太多保留字,而使用 for 来表示条件循环也没有歧义,就没有延用更常见的 while 保留字。

再来做一个和约数有关的问题,分解质因数,这是小学数学课学过的内容。

办法很简单,给定一个正整数 n,我们用 2 去除它,如果能整除,那么就得到它的一个因子 2。我们把 n 除以 2 得到一个新的 n,继续用 2 去除,…;直接不能被 2 整除为止,如果这时候 n 变成 1 了,那就结束了。如果 n 还不是 1,那么继续用 3 去除,重复这个过程;继续用 4,5,…;最后总会会把 n 变成 1,事情就结束了。

还是之前说的,因为还没学过集合,我们把找出来的质因数输出出来即可。

假定 n 先填入了 A1 格。


A

B

C

1

7215

=2


2

for A1>1

for A1%B1==0

>output(B1)

3



>A1=A1\B1

4


>B1+=1


注意在 C3 格要用整除 \,否则会算出浮点数,让下一步的 A1%B1 无法继续了。

这是段两层循环的代码,还有单层循环的写法:


A

B

C

D

1

7215

=2



2

for A1>1

if A1%B1==0

>output(B1)


3



>A1=A1\B1

next

4


>B1+=1



把 B2 格的 for 替换成了 if,然后增加了 D3 格的 next。

if 的作用我们已经知道了,这里的 next 是做什么用的?

next 的意思是进行下一轮循环头,不再执行循环体后面还没有执行过的代码。在这里,如果执行到 D3 的 next,就意味道着 B4 将被跳过不再执行,而直接进入下一轮循环,也就是再转回到 A2 来判断 A1>1 以决定继续执行循环体。

仔细思考这个逻辑过程,B1 开始是 2,如果 A1 能被 2 整数,那么在 C2 中输出这个 2 之后,并把 A1 除以 2,然后再次回到 A2 进入下一轮循环。这时候 B1 还是 2,因为 next 会跳过 B4,其中的语句 B1+=1 并没有被执行。要把所有的因子 2 都除掉之后,这时候会导致 B2 格的 if 不成立,才会进入 B4 格来执行 B1+=1,将 B1 变成 3,再进入下一轮循环。这个单层循环可以做到和上面两层循环同样的效果。

需要说明的是,如果把 next 用到 for n 或 for a,b 的循环中,在下一轮循环时,循环变量仍然会改变。比如前面那个求奇数和的例子,也可以用 next 来写:


A

B

C

1

=0



2

for 200

if A2%2==0

next

3


>A1+=A2


碰到偶数时,B2 的条件成立,就会执行到 C2 的 next,进入下一轮循环,循环变量仍然会加 1;而奇数时将会执行到 B3 来执行累加,循环体将被执行 200 次。

多层循环时,next 后加上循环格的名字,还可以直接让外层循环进入下一轮,比如前面讲过的水仙花数,也可以这么写:


A

B

C

D

E

F

1

for 9

=100*A1

=A1*A1*A1




2


for 0,9

=B1+10*B2

=C1+B2*B2*B2

if C2<D2

next A1

3



for 0,9

=C2+C3

=D2+C3*C3*C3


4




if D3==E3

>output(D3)


5




else if D3<E3

next B2


看起来使用 next 达到了和 break 同样的效果,但其机理却不一样。E5 格的 next B2 会直接进入 B2 循环的下一轮,而如果是 break 则是跳出 C3 循环。在这个例子中,两者效果相同,是因为在 C3 循环结束后也不再有 B2 循环的代码,B2 循环也结束了。

如果代码改成这样:


A

B

C

D

E

F

1

for 9

=100*A1

=A1*A1*A1




2


for 0,9

=B1+10*B2

=C1+B2*B2*B2

if C2<D2

next A1

3



for 0,9

=C2+C3

=D2+C3*C3*C3


4




if D3==E3

>output(D3)


5




else if D3<E3

next B2


6



>output("B2")




E5 代码是 next B2 时,C6 格不会被执行到;如果是 break,则 C6 格还将被执行。读者可以自己尝试一下体会这之间的差别。

【程序设计】 前言及目录

【程序设计】3.2 [做循环] 多层循环

【程序设计】3.4 [做循环] 死循环