跳转到内容

第四章 循环控制

  1. for循环语句格式与执行流程
  2. while循环语句格式与执行流程
  3. do while循环语句格式与执行流程
  4. 三种循环的相互转换
  5. 逗号表达式的执行规则
  6. break语句的作用与适用范围
  7. continue语句的作用
  8. 死循环的构造与退出
  9. 枚举法的基本思想与实现
  10. 贪婪法的基本思想与局限性
  • 循环三要素:循环初始条件、循环终止条件、循环控制变量的更新规则(趋向终止条件)
    [来源:第4章 p3]

  • 循环周期:循环体所有语句的一次完全执行称为一个循环周期
    [来源:第4章 p9,Notes]

  • 需要多次重复执行某任务的问题考虑使用循环来解决
    [来源:第4章 p3]

  • 计算机善于完成繁重的、但有规律的重复性计算,这是采用循环控制的内在逻辑
    [来源:第4章 p2]


  • for语句格式:
    for(表达式1; 表达式2; 表达式3) 语句
    • 表达式1:初始化循环控制变量
    • 表达式2:循环控制条件(可转换为bool的表达式;结果为0/false则退出循环)
    • 表达式3:每个循环周期结束后对循环控制变量的修正
      [来源:第4章 p9]
  • for循环执行过程:
    1. 计算表达式1(初始化循环控制变量)
    2. 计算表达式2(循环控制条件)
    3. 如果表达式2结果非0(true),执行循环体,然后计算表达式3,回到步骤2
    4. 如果表达式2结果为0(false),for语句执行结束
      [来源:第4章 p9]
  • 典型for循环示例:

    for (int i = 0; i < 100; i++) ... // 从0到99
    for (int i = 100; i > 1; i -= 2) ... // 从100递减,步长2

    [来源:第4章 p9]

  • 从1加到100的标准写法:

    int i, s = 0;
    for (i = 1; i <= 100; ++i) s += i;

    [来源:第4章 p10]

  • for括号内声明的循环变量(如 for (int i = 1; ...))具有for语句作用域:它是一个新的局部变量,可遮蔽同名外部变量;若需要在循环外继续使用该变量,应在循环外定义
    [来源:第4章 p10,Notes]

  • 最佳实践:使用标准格式,循环控制变量外围无定义;规则放在括号里,要执行的放在循环体里
    [来源:第4章 p10,Notes]

  • for循环语句很方便用于确定循环次数的循环控制
    [来源:第4章 p14]

  • ⚠️ 变量s必须初始化为0,否则结果不确定
    [来源:第4章 p10,Notes]

  • ⚠️ for循环中的表达式3是在所有循环内语句执行结束之后才执行的,需特别注意执行顺序
    [来源:第4章 p18,Notes]


  • 逗号表达式格式:
    表达式1, 表达式2, ..., 表达式n
    [来源:第4章 p11]
  • 逗号表达式执行过程:
    1. 逗号运算符起分割作用
    2. 先执行表达式1,再执行表达式2,...,再执行表达式n(从左到右)
    3. 整个表达式的计算结果为最后一个表达式的值
      [来源:第4章 p11]
  • 示例:若 a 初值为 0,则表达式 a += 1, a += 2, a += 3, a += 4, a += 5 的值为 15,且执行完后 a 的值也变为 15
    [来源:第4章 p11]

  • while语句格式:
    while (表达式) 语句
    // 循环体可以是复合语句或空语句
    [来源:第4章 p16]
  • while循环执行过程:
    1. 计算表达式的值(作为循环控制条件)
    2. 如果为0,循环终止,执行while循环之后的语句
    3. 如果非0,执行整个循环体
    4. 重复上述过程
      [来源:第4章 p16]
  • 求e^x的级数展开(当某一项的绝对值小于阈值时结束循环):
    ex = 0; p = 1; i = 0;
    while (fabs(p) > 1e-6) {
    ex += p;
    ++i;
    p = p * x / i;
    }
    [来源:第4章 p17]

4.5 for与while的相互转换

跳转到:4.5 for与while的相互转换
  • for语句改写为while语句的方法:
    // for形式
    for(表达式1; 表达式2; 表达式3) 语句
    // 等价的while形式(若循环体中没有continue;如有continue需确保仍执行“表达式3”)
    表达式1;
    while(表达式2) {
    语句;
    表达式3;
    }
    [来源:第4章 p18]
  • 转换示例:
    // for形式
    for(double x = a + dlt/2; x < b; x += dlt)
    integral += (x*x + 5*x + 1) * dlt;
    // while形式
    double x = a + dlt/2;
    while(x < b) {
    integral += (x*x + 5*x + 1) * dlt;
    x += dlt;
    }
    [来源:第4章 p18]

  • do...while语句格式:
    do 语句 while (表达式);
    // 循环体可以是复合语句或空语句
    // 注意末尾有分号
    [来源:第4章 p20]
  • do...while执行过程:先执行循环体,然后判断循环条件,如条件成立,继续循环,直到条件为假
    [来源:第4章 p20]
  • ⚠️ while与do while的核心区别:
    • while:先判断后执行,循环体可能一次都不执行
    • do while:先执行后判断,循环体至少执行一次
      [来源:第4章 p20]
  • 输入数据累加直到输入0为止:

    total = 0;
    do {
    cout << "Input a number:";
    cin >> value;
    total += value;
    } while (value != 0);

    [来源:第4章 p20]

  • 二分法求方程根(x³+2x²+5x-1=0 在[-1,1]区间):

    double x, x1 = -1, x2 = 1, fx1, fx;
    do {
    fx1 = x1*x1*x1 + 2*x1*x1 + 5*x1 - 1;
    x = (x1 + x2) / 2;
    fx = x*x*x + 2*x*x + 5*x - 1;
    if (fx * fx1 > 0) x1 = x; else x2 = x;
    } while (fabs(fx) > 1e-7);

    [来源:第4章 p22]


4.7 死循环与中途退出

跳转到:4.7 死循环与中途退出
  • 死循环:循环控制条件永远为真的循环
    [来源:第4章 p24]

  • 构造死循环的方式:

    for (;;); // 三个表达式均省略;其中表达式2省略时默认为true(死循环)
    for (;true;) ... // 表达式2恒为true
    for (;1;) ... // 表达式2恒为非0
    while (true) ... // 条件恒为true

    [来源:第4章 p24]

  • 运行时跳出死循环:通常可用 Ctrl+C(命令行)或 IDE 的 Stop/Terminate 按钮中断(取决于运行环境)
    [来源:第4章 p24]

  • 死循环设置好退出机制后是有用的(如cin等待输入)
    [来源:第4章 p24,Notes]


  • break语句:用于跳出一个循环体或switch体
    [来源:第4章 p26]
  • break的适用范围:对于嵌套结构,break只能跳出其所在的底层结构
    [来源:第4章 p26]

  • break一般与if语句配合使用,if负责检查终止条件,条件满足后break结束循环
    [来源:第4章 p25,Notes]

  • 使用break的死循环模式:
    while (true) {
    // 提示用户并读入数据
    if (value == 标志) break; // break语句跳出循环
    // 对数据作出处理
    }
    [来源:第4章 p25]
  • 【执行结果分析】 嵌套结构中switch内的break退出switch,while内的break退出while:
    for (int i = 0; i < 2; i++) {
    while(1) {
    switch(1) {
    case 1: break; // 退出switch
    case 2: cout << "switch" << endl;
    }
    cout << "while" << endl;
    break; // 退出while
    cout << "behind while break" << endl; // 不执行
    }
    cout << " for loop" << endl;
    }
    输出结果:
    while
    for loop
    while
    for loop
    [来源:第4章 p26]
  • ⚠️ 多层嵌套循环要跳出所有循环,需要多个break配合标志变量:

    bool flag = false;
    for (...) {
    for (...) {
    for (...) {
    if (条件) { flag = true; break; }
    }
    if (flag) break;
    }
    if (flag) break;
    }

    [来源:第4章 p37]

  • 或者将标志变量放入循环条件:

    for (dt = 1; dt <= 4 && !flag; ++dt) {
    for (hz = 1; hz <= 4 && !flag; ++hz) {
    ...
    }
    }

    [来源:第4章 p38]


  • continue语句:跳过本轮循环周期中剩余的语句,直接开始下一轮循环
    [来源:第4章 p25]
  • continue与break的区别:break终止循环,continue跳过当前轮
    [来源:第4章 p25,Notes]

  • 在for循环中,continue会跳过之后语句,直接执行表达式3
    [来源:第4章 p25]

  • 求0至x之间偶数的和:
    int sum, i;
    for (sum = 0, i = 0; i <= x; i++) {
    if (i % 2 != 0) continue; // 奇数跳过
    sum += i;
    }
    [来源:第4章 p25]

  • 枚举法:对所有可能的情况一一去尝试,直到找到正确的答案。非常适合利用计算机求解
    [来源:第4章 p33]
  • 买水果问题(50元买100个水果:西瓜5元、苹果1元、桔子1元3个。下述代码默认每种水果至少买1个;若允许西瓜为0,则还存在 mellon:0 apple:25 orange:75):

    for (mellon = 1; mellon < 10; ++mellon)
    for (apple = 1; apple < 50 - 5*mellon; ++apple) {
    orange = 3 * (50 - 5*mellon - apple);
    if (mellon + apple + orange == 100) {
    cout << "mellon:" << mellon << ' ';
    cout << "apple:" << apple << ' ';
    cout << "orange:" << orange << endl;
    }
    }

    输出结果:

    mellon:1 apple:18 orange:81
    mellon:2 apple:11 orange:87
    mellon:3 apple:4 orange:93

    [来源:第4章 p34]

  • 罗列2到100的素数(或:输出100以内素数):

    for (int i = 2; i <= 100; i++) {
    bool flag = true;
    for (int j = 2; j < i; j++) {
    if (i % j == 0) {
    flag = false;
    break;
    }
    }
    if (flag) cout << i << endl;
    }

    [来源:第4章 p39]

  • 【整理自 PPT】枚举法中,可以按一个约束条件列出所有可行情况,然后检查每个可能解是否满足其他约束条件
    [来源:第4章 p33]

  • 【整理自 PPT】四大湖问题中,布尔条件可以参与加法运算:(a == 1) + (b == 4) + (c == 3) 表示满足条件的个数
    [来源:第4章 p35]


  • 贪婪法:在求解过程的每一步都选取一个局部最优的策略,把问题规模缩小,最后把每一步的结果合并起来形成一个全局解
    [来源:第4章 p41]
  • 硬币找零问题(1分、2分、5分、1角硬币,找K分零钱):
    int money = K;
    int onejiao = 0, fivefen = 0, twofen = 0, onefen = 0;
    while (money >= 10) { ++onejiao; money -= 10; }
    while (money >= 5) { ++fivefen; money -= 5; }
    while (money >= 2) { ++twofen; money -= 2; }
    while (money >= 1) { ++onefen; money -= 1; }
    [来源:第4章 p42]
  • ⚠️ 贪婪法不一定得到最优解! 如果局部最优无法带来全局最优,就不具备贪心选择的性质
    [来源:第4章 p43]

  • 反例:硬币面值为1分、3分、9分、1角时,找27分:

    • 贪婪法:27 = 10 + 10 + 3 + 3 + 1 = 5个硬币
    • 最优解:27 = 9 + 9 + 9 = 3个硬币
      [来源:第4章 p43]

判定条件/等价表述

跳转到:判定条件/等价表述
  • 计算机的强项是不厌其烦地做同样的操作,这是通过循环语句实现的
    [来源:第4章 p44]

  • 三种循环语句:for、while、do while
    [来源:第4章 p44]

  • 枚举法:对某些问题,在寻找解时需要检查所有可能的方案,从中找出可行解
    [来源:第4章 p44]

  • 贪婪法:可用于求问题的最优解,但不一定对所有问题都能得到最优解
    [来源:第4章 p44]


  1. xyz + yzz = 532,x、y、z各代表不同数字,求x、y、z。
    答案:xyz = 321(即 x=3, y=2, z=1)
    [来源:第4章 p45,Notes]

  2. 输出N行等腰三角形:输入整数N,输出由''组成的等腰三角形,下行比上行多两个'',尖角朝上。
    提示:设输入为 N(行数),第 i 行(i 从 0 开始)输出:先输出 (N - i - 1) 个空格,再输出 (2i + 1) 个 '';行尾空格可省略
    [来源:第4章 p45,Notes]

  3. 求x的平方根(迭代法):

    • (1) Root = x/2
    • (2) 检查 root*root 和 x 的差
    • (3) 按 root = (root + x/root)/2 更新
    • (4) 重复直到误差小于1%
      [来源:第4章 p45]

根据PPT第7页的学习目标:

  • ✅ for, while, do while:熟练掌握一种循环结构
  • ✅ 另外两种:会读即可
  • ✅ 会使用 break、continue 编程

[来源:第4章 p7,学习目标]