Lesson 0006 · 嵌套循环

① 程序设计基础 — 第 5 课

上节课:string 和 vector 让数据处理方便很多。但遇到「去重」这类题时会发现,一个循环不够用 —— 得在循环里再套一个循环。
这节课:专门讲嵌套循环。它干的事就一件:处理二维的东西 —— 表格的行和列、图形的每一行、以及「每个元素都要和别的元素比一遍」。
三句话速览

1. 嵌套循环是什么

一句话:外层走一步,内层跑一圈。

for (int i = 0; i < 3; i++) {
    for (int j = 0; j < 2; j++) {
        cout << "(" << i << "," << j << ") ";
    }
    cout << endl;
}
// 输出:
// (0,0) (0,1)
// (1,0) (1,1)
// (2,0) (2,1)

执行顺序:i=0 → j=0,j=1 → 换行 → i=1 → j=0,j=1 → 换行 → i=2 → j=0,j=1

2. 经典用法

打印乘法表

for (int i = 1; i <= 9; i++) {             // 行
    for (int j = 1; j <= i; j++) {         // 列(每行列数递增)
        cout << j << "x" << i << "=" << i*j << "\t";
    }
    cout << endl;
}
// 输出经典的九九乘法表

打印图形

// 直角三角形
for (int i = 1; i <= 5; i++) {
    for (int j = 1; j <= i; j++) {
        cout << "*";
    }
    cout << endl;
}
/*
*
**
***
****
*****
*/

3. 嵌套循环 + 一维数组 = 去重

这就是你上节课卡住的那道题。核心思路:

vector<int> v = {3, 1, 4, 1, 5, 4};
vector<int> result;

for (int i = 0; i < v.size(); i++) {           // 外层:看每个数
    bool already = false;
    for (int j = 0; j < result.size(); j++) { // 内层:查 result 里有没有
        if (v[i] == result[j]) {
            already = true;
            break;           // 找到了,不用继续查
        }
    }
    if (!already) result.push_back(v[i]);     // 没找到,加进去
}
// result = {3, 1, 4, 5}
理解关键:外层 v[i] 每取一个数,内层就把 result 扫一遍。result 只存"第一次出现"的数。

4. 嵌套循环 + vector = 排序

冒泡排序(经典中的经典)

vector<int> v = {5, 3, 8, 1, 2};
int n = v.size();

for (int i = 0; i < n - 1; i++) {             // 外层:第几轮
    for (int j = 0; j < n - 1 - i; j++) {     // 内层:两两比较
        if (v[j] > v[j + 1]) {                // 前面比后面大就交换
            int temp = v[j];
            v[j] = v[j + 1];
            v[j + 1] = temp;
        }
    }
}
// v = {1, 2, 3, 5, 8}

每轮把最大的"冒"到最后面。外层控制轮次,内层做比较交换。

5. 性能意识

嵌套循环 = n x m 次操作。1000 个数两两比较就是 100 万次。遇到大数组时嵌套循环会慢,但学算法之前先会用就够了。

6. 坑点清单

7. 小测

Q1. 外层 3 次,内层 4 次,循环体执行几次?
Q2. 去重里内层为什么要用 break?
Q3. 冒泡排序外层循环 i < n - 1,为什么是 n-1 不是 n?

8. 动手练习

题目1:打印三角形

输入 n,打印 n 行的三角形:第一行 1 个 *,第 i 行 i 个。
示例:n=4 → 输出一个垂直的 4 行三角形。
题目2:去重(二刷)

用今天学的嵌套循环,重写去重。读入 n 个数,输出去重结果。
示例:6 → 3 1 4 1 5 4 → 3 1 4 5

卡住时的自查顺序

  1. 先把外层写成「只打第 i 行」,确认行数和换行对不对,内层再做打印。
  2. 内层的上界是不是依赖外层?三角形用 j <= i,从 1 开始更省事。
  3. 每行打完后有没有 cout << endl;?忘了就全挤在一行。
  4. 去重题:already 是不是写在外层循环体里面、每轮重置成 false?

本课小结

下一课预告
0007 指针与引用 —— 循环和容器都学过了,下一课往下钻一层:变量在内存里到底放在哪,& 和 * 分别是什么意思,为什么要传引用。
嵌套循环是后面所有算法题的骨架(枚举、排序、矩阵),先把「外层管什么、内层管什么」想清楚再动手敲。哪一句还不明白 —— 比如「内层循环能不能依赖外层的值」「break 怎么一次跳出两层」「冒泡为什么每轮少比一个」—— 直接问。

Lesson 0006 · 课程体系总览:curriculum-overview.html

上一课:string 与 vector · Mission · Notes

书 C++ Primer 第 5 章(语句) · STL 速查表