文章

【GESP】C++二级考试大纲知识点梳理, (8)多层循环结构

如果说单层循环是“跑圈”,那么多层循环就是“时钟”。掌握多层循环,就能解决著名的“打印图形”和“穷举求解”类问题,这是二级考试中最核心的难点之一。本篇详细剖析大纲第 8 条考点。

(8)掌握多层循环结构,掌握 for 语句、while 语句、do…while 语句,及相互嵌套的方法。

二级考点系列:


一、嵌套循环的“时钟模型”

1.1 什么是嵌套循环?

简单说,就是在一个循环体里面,再写一个循环。 forforwhilewhile,或者 forwhile 都可以。

1.2 核心逻辑:外层走一步,内层跑一圈

想象一个时钟:

  • 外层循环好比时针
  • 内层循环好比分针

时针走 1 格(外层循环执行 1 次),分针就要走 60 格(内层循环要把它的所有次数都执行完)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 外层循环:i 从 1 到 3
for (int i = 1; i <= 3; i++) {
    cout << "外层第" << i << "次: ";
    
    // 内层循环:j 从 1 到 5
    // 【重点】每次外层进来,j 都会重新从 1 开始!
    for (int j = 1; j <= 5; j++) {
        cout << j << " ";
    }
    cout << endl;
}
/* 输出:
外层第1次: 1 2 3 4 5 
外层第2次: 1 2 3 4 5 
外层第3次: 1 2 3 4 5 
*/

二、经典应用 1:打印图形

在二级考试中,打印图形是嵌套循环最直观的应用。 解题口诀

  1. 外层循环控制行数(高度)。
  2. 内层循环控制列数(每一行打印的内容)。
  3. 找规律:找到每一行的符号数量与行号 i 的关系。

2.1 打印矩形

打印 $n$ 行 $n$ 列的星号。

1
2
3
4
5
6
for (int i = 1; i <= n; i++) {       // 控制行
    for (int j = 1; j <= n; j++) {   // 控制列
        cout << "*";
    }
    cout << endl; // 每一行结束记得换行!
}

2.2 打印直角三角形

第 1 行 1 个星,第 2 行 2 个星 … 第 $i$ 行 $i$ 个星。

  • 行数:$1 \sim n$
  • 列数:$1 \sim i$ (内层循环的终点是变量 $i$)
1
2
3
4
5
6
7
for (int i = 1; i <= n; i++) {
    // 这里的 j <= i 是关键!
    for (int j = 1; j <= i; j++) {
        cout << "*";
    }
    cout << endl;
}

2.3 打印乘法口诀表

这就和直角三角形一模一样!

1
2
3
4
5
6
for (int i = 1; i <= 9; i++) {
    for (int j = 1; j <= i; j++) {
        cout << j << "*" << i << "=" << i*j << "\t";
    }
    cout << endl;
}


三、经典应用 2:穷举求解 (暴力破解)

计算机最擅长的就是“笨办法”——把所有可能性都试一遍。这就是穷举法(Enumeration)。 对于多变量问题,通常用多层循环来实现。

3.1 案例:百钱百鸡

题目:公鸡 5 元一只,母鸡 3 元一只,小鸡 1 元 3 只。用 100 元买 100 只鸡,问公鸡、母鸡、小鸡各多少只?

分析

  • 设公鸡 $x$ 只,母鸡 $y$ 只,小鸡 $z$ 只。
  • 条件 1:$x + y + z = 100$
  • 条件 2:$5x + 3y + z/3 = 100$ (这里的 $z/3$ 在编程中要注意整除问题,最好写成 $15x + 9y + z = 300$ 或者保证 $z \% 3 == 0$)

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 确定边界:100元全买公鸡最多20只,全买母鸡最多33只
for (int x = 0; x <= 20; x++) {
    for (int y = 0; y <= 33; y++) {
        // 【优化技巧】小鸡不用循环试,直接算出来!
        int z = 100 - x - y;
        
        // 验证条件:
        // 1. 钱数总和为100
        // 2. 小鸡必须是3的倍数(题目说1元3只,通常隐含整数买卖)
        if (z % 3 == 0 && 5 * x + 3 * y + z / 3 == 100) {
            cout << "公鸡:" << x << " 母鸡:" << y << " 小鸡:" << z << endl;
        }
    }
}

四、break 和 continue 在嵌套中的表现

breakcontinue 只对它所在的“那一层”循环有效!不能直接跳出多层循环。

1
2
3
4
5
6
7
8
9
10
for (int i = 1; i <= 3; i++) {
    for (int j = 1; j <= 5; j++) {
        if (j == 3) break; // 只跳出内层循环!
        cout << "(" << i << "," << j << ") ";
    }
    cout << "EndInner ";
}
/* 输出片段:
(1,1) (1,2) EndInner (2,1) (2,2) EndInner ...
*/

如果想直接跳出所有循环(比如找到了答案),通常有两种办法:

  1. 使用 goto 语句(虽不推荐但有效)。
  2. 设置一个 bool 旗帜变量,在外层检测到旗帜也进行 break
  3. 直接 return 0 结束整个程序。

五、时间复杂度初探

虽然二级不考复杂的算法分析,但要有效率意识

  • 单层循环 $n$ 次:复杂度 $O(n)$。
  • 双层循环 $n \times n$ 次:复杂度 $O(n^2)$。

当 $n = 1000$ 时:

  • $O(n)$ 大约运行 1000 次,瞬间完成。
  • $O(n^2)$ 大约运行 1,000,000 次(一百万),也很快。
  • 但如果 $n = 100000$,$O(n^2)$ 就是 100 亿次,现在的普通电脑就要跑几十秒甚至更久了(超时)。

所以在写多层循环时,要看看 $n$ 有多大。对于 $n \le 1000$ 的范围,双层循环通常是安全的。


所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code

GESP 学习专题站:GESP WIKI

luogu-”系列题目可在洛谷题库进行在线评测。

bcqm-”系列题目可在编程启蒙题库进行在线评测。

欢迎加入Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答

欢迎加入C++ GESP/CSP认证学习QQ频道,考试资源总结汇总

欢迎加入C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助

GESP/CSP 认证学习微信公众号
GESP/CSP 认证学习微信公众号
本文由作者按照 CC BY-NC-SA 4.0 进行授权