vlambda博客
学习文章列表

C语言拓展第五期:循环(二)

C语言循环篇(二)



写在前面:

之前在C语言循环篇(一)中我们初步学习了for、while、do-while的基本语法,那么接下来我们将来更加深入地探索使用循环我们可以办到的事情。


我们现在可以办到的事情其实还是相当有限的,但其实我们已经可以将目前的知识用于解决一些实际问题了。

鸡兔同笼问题

小学的数学课(或者算数课)肯定会讲到一道题,叫做鸡兔同笼问题,问题描述很简单,有一堆兔子和鸡被装在一个笼子里,已知的是它们的总数和脚的总数,最简单的方法是利用一个二元一次方程组来解决问题(设鸡的数量为x只,兔子为y只,总共有59只,总共的脚有172个):
然后愉快地解出这个方程式就好,那么我们能不能用程序解决这个问题呢?答案自然是肯定的,先让我们看一下这个使用到 循环和判断的程序:
 
   
   
 
#include<stdio.h>

int main(){
int chicken_nums = 0;
int rabbit_nums = 0;
for(chicken_nums = 0; chicken_nums <= 59; chicken_nums++){ // 第一个chicken_nums可以不写,因为已经在外部初始化了
rabbit_nums = 59 - chicken_nums;
if(2 * chicken_nums + 4 * rabbit_nums == 172){ // 一定注意在C语言(或其他绝大多数语言)中“=”是赋值符号,而“==”才是判断是否相等的符号
printf("鸡的数量为%d,兔子的数量为%d",chicken_nums, rabbit_nums);
break;
}
if(chicken_nums == 59)
printf("该问题无解");
}
return 0;
}
C语言拓展第五期:循环(二)
在上面那段程序中在一个for循环中还嵌套了两个if语句,整个程序的执行顺序是这样的:
 
   
   
 
循环开始,初始化chicken_nums = 0,判断是否继续执行的条件为:chicken_nums <= 59,执行完毕后将自加1
|
|-定义rabit_nums的值,保证其与chicken_nums相加为59
|
|-if语句:如果假定的鸡兔数量的脚的总数符合题目要求,则打印答案并跳出循环
|
|-if语句:如果此时chicken_nums的值已经为59(即已经遍历了所有答案但都不对),则此问题无解
可以看到通过这样的一次循环我们遍历了所有可能的答案,这也就是“穷举法”,另外在这段程序中多了一个break语句:
 
   
   
 
for(;;){ // 这里也可以是while或do-while
...
break;
...
}
这个break可以在任何地方,上面的例子中它就在一个判断语句里(但一定要保证它必须在一个循环的循环体中),它的作用就是 立即跳出当前所在循环体的循环。
也就是如果它在一个 循环嵌套的语句中,那么在下面这种情况下只会跳出嵌套的循环语句(外部循环依旧执行):
 
   
   
 
for(;;){
for(;;){
break;
}
}
与break相对应的就是continue,他的作用是跳出当前的一次循环,直接进入下一次循环中,下面举个例子:
 
   
   
 
#include <stdio.h>

int main(){
for(int i = 0; i <= 10; i++){
if(i == 5)
continue;
printf("%d\n", i);
}
return 0;
}
C语言拓展第五期:循环(二)
可以从结果看到最后打印跳过了5,但如果把continnue换成break,那么结果将变为:
接下来让我们看一个应用循环嵌套的实际例子:
解下列一个三元一次方程
 
   
   
 
#include <stdio.h>

int main(){
int x = 0;
int y = 0;
int z = 0;
while(1){
y = 0;
while(1){
z = 0;
while(1){
if(2 * x + 3 * y + z == 6 && x - y + 2 * z == 2 && x + 2 * y - z == 2){
printf("x=%d, y=%d, z=%d", x, y, z);
return 1;
}
if(z == 20)
break;
z++;
}
if(y == 20)
break;
y++;
}
if(x == 20)
break;
x++;
}
printf("该问题无解");
return 0;
}
while(1)表示该循环会一直执行下去,包括for也是,判断循环执行的条件只要为真,循环就会执行,而在C语言中0也可以表示假,1(或其他整数)也可以表示真。
上面这个程序可能看起来相当眼晕,但只要分清楚每一层循环在干什么,整个问题也就清晰可见了:
 
   
   
 
// 第一层循环:
while(1):
y = 0; // 保证每次当x自增时,y重新从0开始
......
if(x === 20) // 若x到达上限则跳出当前循环,也可以在定义循环时写while(x <= 20)
break;
x++;

// 第二层循环和第一层几乎一样:
while(1):
z = 0; // 保证每次当x自增时,z重新从0开始
......
if(y === 20) // 若x到达上限则跳出当前循环,也可以在定义循环时写while(y <= 20)
break;
y++;

// 第三层循环则在此基础上稍加了一个判断条件:
while(1){
if(2 * x + 3 * y + z == 6 && x - y + 2 * z == 2 && x + 2 * y - z == 2){ // 如果找到答案,则打印并且跳出main函数
printf("x=%d, y=%d, z=%d", x, y, z);
return 1;
}
if(z == 20)
break;
z++;
先不谈论遇到的新符号&&和return关键字,通过梳理我们可以理出整个循环遍历所有可能答案时的顺序:
 
   
   
 
// 第1次循环:
x=0,y=0,z=0
// 第2次循环:
x=0,y=0,z=1
// 第3次循环:
x=0,y=0,z=2
......
// 第21次循环:
x=0,y=0,z=20
// 第22次循环:
x=0,y=1,z=0
// 第23次循环:
x=0,y=1,z=0
......
// 第441次循环:
x=0,y=20,z=20
// 第442次循环:
x=1,y=0,z=0
......
// 第463次循环:
x=1,y=1,z=0
// 第464次循环:
x=1,y=1,z=1
判断条件成功,打印结果并退出
接下来说说&&代表的意思,这个符号是“逻辑与”,代表着两边的条件必须同为真才能返回真,比如:
 
   
   
 
1 < 2 && 2 < 3 // 返回真,因为两边都为真
    1 > 2 && 2 < 3 // 返回假,因为两边不全为真
    1 > 2 && 2 > 3 // 返回假,因为两边不全为真
当然还有“逻辑或”以及“逻辑非”等符号,这些符号等我们遇到再做解释。
最后就是return这个关键字了,就像break跳出循环一样,当程序执行遇到它是会直接跳出当前的函数,像我们目前为止写过的所有例子都是在main函数里完成的,当程序执行到return后就会直接中止掉当前函数,因此后面的循环和打印语句就不会再发生了。
C语言规定程序的入口必须为main函数,也就是一个程序中有且只能有一个main函数存在,这也就是我们所有的例子都写在main函数中的原因。
最后,在写循环嵌套结构的时候要注意整个逻辑链的正确,最好能画个NS图或者在纸上写一下流程再着手遍程也不晚。