跳转至

7. 循环结构

7.1 whiledo ... whilefor

三种循环先分清判断时机:while 先判断,第一次条件就不成立时一遍也不执行;do ... while 先做一遍再判断,所以至少执行一次;for 只是把初始化、条件和更新集中写在了一行。

while (condition) {
    /* 循环体 */
}

do {
    /* 循环体 */
} while (condition);

for (初始化; 条件; 更新) {
    /* 循环体 */
}

循环写错往往不是语法问题,而是差一轮。拿不准 < 还是 <= 时,别凭感觉,直接把第一次和最后一次循环的变量值写在纸上。

for 的三个表达式均可省略。省略条件相当于真,但循环仍要通过 break 等方式退出。

中间的表达式是“循环是否继续”的条件,不是“满足后只执行一次”的 if。另外,while (条件); 后面那个分号代表空循环体;条件一直为真时,后面的花括号永远也执行不到。

7.2 嵌套、breakcontinue

循环嵌套时,每执行一轮外层循环,内层循环都要从头跑一遍。因此内层循环变量要重新初始化;忘了这一点,第二轮外循环里内层循环可能一次也不进。

  • break 只跳出它所在的最内层循环或 switch
  • continue 跳过本轮余下语句,进入下一轮;
  • for 中,continue 后先执行更新表达式;在 while 中则直接判断条件,注意不要漏掉必要的状态更新。

break 只能跳一层。要一次离开多层循环,可以设标志,也可以把这段搜索单独写成函数,找到答案就直接 return

7.3 输入循环

连续读数据时,直接拿输入函数的返回值控制循环最省心:

int x, sum = 0;
while (scanf("%d", &x) == 1 && x > 0) {
    sum += x;
}

while (!feof(stdin)) 看起来合理,实际会慢一拍:只有读取已经失败,文件结束标志才会出现,上一组数据可能因此被处理两遍。

7.4 常用算法思路

候选范围不大时可以直接列举,把所有可能都试一遍;如果候选需要边生成边调整,就是试探法。课件里的密码问题、四叶玫瑰数都属于这一类。这些题的循环通常不难,难的是有没有漏掉判定条件。

整数拆位经常成对出现:n % 10 取出个位,n /= 10 再删掉个位。例如判断回文数,就是一边取位一边拼出逆序数。

数值计算题则是另一套循环:级数求和要同时更新通项和总和;二分求根每次保留仍然夹着根的半个区间;梯形积分把区间切成小段后逐段累加。这里的循环次数或误差阈值都要写清楚,否则很容易多算一项或一直不结束。

评论