- juxq 的博客
流程控制之循环结构教学讲义
- @ 2026-4-4 11:31:58
流程控制之循环结构教学讲义
1. 循环结构简介
1.1 什么是循环结构
循环结构(Loop Structure):根据某个条件是否满足,重复执行一段代码块。它使计算机能够高效地处理大量重复性工作。
现实世界中存在大量重复操作:“从1加到100”、“重复打印10次Hello”……如果没有循环,我们需要把相同的代码写100遍,这显然不可行。循环结构正是为解决这类问题而诞生的。
图示:循环执行流程
┌─────────────┐
│ 循环条件 │
└──────┬──────┘
│
┌────────┴────────┐
│ 真(true) │ 假(false)
▼ ▼
┌───────────┐ ┌───────────┐
│ 循环体 │ │ 退出循环 │
└─────┬─────┘ └───────────┘
│
└──→ 返回判断条件
1.2 为什么需要循环结构
- 避免代码重复:用几行代码代替成百上千行的重复代码。
- 处理批量数据:如输入100个学生的成绩、计算1~100的和。
- 实现复杂算法:排序、查找、穷举、模拟等都依赖循环。
2. 循环结构的类型
C++ 提供了四种主要的循环语句。
2.1 while 循环(前置条件循环)
格式:先判断条件,条件为真时才执行循环体;可能一次都不执行。
while (循环条件表达式) {
循环体;
}
示例:计算 1 + 2 + ... + n。
int i = 1, sum = 0;
while (i <= n) {
sum += i;
i++;
}
图示:
判断条件
│
┌───┴───┐
是 否
│ │
▼ ▼
执行循环体 退出
│
└──→ 返回判断
2.2 do-while 循环(后置条件循环)
格式:先执行一次循环体,再判断条件;至少执行一次。
do {
循环体;
} while (循环条件表达式);
示例:同样计算 1~n 的和。
int i = 1, sum = 0;
do {
sum += i;
i++;
} while (i <= n);
区别:while 可能一次都不执行,do-while 至少执行一次。适用于“先执行再判断”的场景(如菜单输入)。
2.3 for 循环(计数循环)
格式:将循环变量初始化、条件判断、变量更新三部分集中在一起,结构清晰。
for (循环变量初始化; 循环条件; 循环变量更新) {
循环体;
}
示例:计算 1~n 的和。
int sum = 0;
for (int i = 1; i <= n; i++) {
sum += i;
}
执行顺序:
- 执行初始化(仅一次)
- 判断循环条件,为真则进入循环体,否则退出
- 执行循环体
- 执行变量更新
- 返回第2步
for 循环的各种变形:
- 省略初始化:
int i = 1; for (; i <= n; i++) - 省略更新:
for (int i = 1; i <= n; ) { ... i++; } - 无限循环:
for (;;) { ... }
2.4 无限循环
当循环条件永远为真时,循环永不结束。通常配合
break在内部退出。
while (true) {
// 循环体
if (退出条件) break;
}
或 for (;;) { ... }
示例:使用无限循环计算 1~n 的和。
int i = 1, sum = 0;
while (true) {
sum += i;
i++;
if (i > n) break;
}
注意:无限循环必须有退出机制(
break或return),否则程序会“卡死”。
2.5 循环嵌套
在一个循环的循环体内再包含另一个完整的循环结构,称为循环嵌套。外层循环每执行一次,内层循环会完整执行一轮。
示例:输入一个 n×m 的矩阵。
for (int i = 1; i <= n; i++) { // 外层循环:行
for (int j = 1; j <= m; j++) { // 内层循环:列
cin >> num;
}
}
复杂度:外层循环 n 次,内层循环 m 次,总循环次数为 n×m。
2.6 break 和 continue
break:强制终止整个循环,跳出当前循环体(只影响所在的最内层循环)。continue:跳过本次循环剩余代码,立即进入下一次循环判断。
示例:输出 5~10(跳过 1~4)。
for (int i = 1; i <= 10; i++) {
if (i < 5) continue;
cout << i << endl;
}
// 输出:5 6 7 8 9 10
示例:素数判定(找到第一个因子后立即退出)。
bool isPrime = true;
for (int i = 2; i * i <= n; i++) {
if (n % i == 0) {
isPrime = false;
break; // 无需继续检查
}
}
3. 经典问题示例
3.1 角谷猜想(3n+1 问题)
任意正整数,如果是奇数则乘以3加1,如果是偶数则除以2,重复操作,最终都会变为1。
int n;
cin >> n;
while (n > 1) {
if (n % 2 == 1) {
n = n * 3 + 1;
} else {
n /= 2;
}
cout << n << endl;
}
3.2 百钱买百鸡
公鸡5元,母鸡3元,小鸡1/3元(即3只1元)。用100元买100只鸡,求各买多少只。
优化解法(双重循环 + 剪枝):
for (int i = 1; i <= 20; i++) { // 公鸡最多20只(5*20=100)
for (int j = 1; j <= 33; j++) { // 母鸡最多33只(3*33=99)
int k = 100 - i - j; // 小鸡数量由总数推导
if (5 * i + 3 * j + k / 3.0 == 100) {
cout << "公鸡:" << i << ",母鸡:" << j << ",小鸡:" << k << endl;
}
}
}
3.3 鸡兔同笼
已知头数和脚数,求鸡兔各多少只。数学解法 O(1):
int head, foot;
cin >> head >> foot;
int rabbit = (foot - 2 * head) / 2; // 或 (4*head - foot)/2
int chicken = head - rabbit;
cout << "兔:" << rabbit << ",鸡:" << chicken << endl;
4. 课堂例题
例题1:求最大公约数(辗转相除法)
题目描述
输入两个正整数
a和b(1 ≤ a,b ≤ 10⁹),求它们的最大公约数(GCD)。输入:一行两个整数。 输出:一个整数,表示最大公约数。
思路解析
辗转相除法(欧几里得算法):gcd(a, b) = gcd(b, a % b),重复直到余数为0。这个过程天然适合循环实现。可以用 while 循环不断取余,直到余数为0,此时的除数即为最大公约数。
代码实现
#include <bits/stdc++.h>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
// 辗转相除
while (b != 0) {
int r = a % b;
a = b;
b = r;
}
cout << a << endl;
return 0;
}
注:也可以使用
__gcd(a, b)内置函数,但理解算法原理更重要。
例题2:水仙花数
题目描述
水仙花数是指一个三位数,其各位数字的立方和等于该数本身。例如:153 = 1³ + 5³ + 3³。输出所有的水仙花数,每个数占一行。
输出:所有符合条件的三位数,每行一个。
思路解析
遍历100~999之间的所有数,对每个数提取百位、十位、个位,计算立方和并判断是否等于原数。循环结构(for)非常适合这种“枚举”场景。
代码实现
#include <bits/stdc++.h>
using namespace std;
int main() {
for (int i = 100; i <= 999; i++) {
int a = i / 100; // 百位
int b = i / 10 % 10; // 十位
int c = i % 10; // 个位
if (a*a*a + b*b*b + c*c*c == i) {
cout << i << endl;
}
}
return 0;
}
例题3:打印九九乘法表
题目描述
输出九九乘法表,格式如下(每个算式占4个字符宽度,左对齐):
1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 ... 1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
思路解析
双重循环:外层控制行数(1~9),内层控制列数(1~行数)。注意每行输出结束后换行。使用 setw(4) 控制宽度。
代码实现
#include <bits/stdc++.h>
using namespace std;
int main() {
for (int i = 1; i <= 9; i++) { // 行(乘数1)
for (int j = 1; j <= i; j++) { // 列(乘数2)
cout << j << "*" << i << "=" << setw(2) << i*j << " ";
}
cout << endl;
}
return 0;
}
扩展:可以尝试输出右上三角、右下三角等变体。
5. 课后练习
以下题目建议在洛谷(luogu.com.cn)上完成,涵盖循环结构的各种应用。
| 序号 | 题目名称 | 链接 | 知识点 |
|---|---|---|---|
| 1 | 【深基4.例2】找最小值 | P5718 | 循环 + 打擂台 |
| 2 | 【深基4.例3】分类平均 | P5719 | 循环 + 条件统计 |
| 3 | 【深基4.例4】一尺之棰 | P5720 | while 循环 |
| 4 | 【深基4.例6】数字直角三角形 | P5721 | 循环嵌套 + 输出格式 |
| 5 | 质数口袋 | P5723 | 循环 + 素数判定 + break |
| 6 | 阶乘之和 | P1009 | 循环嵌套(高精度可选) |
| 7 | 级数求和 | P1035 | 循环累加直到满足条件 |
| 8 | 角谷猜想 | P5727 | while 循环 + 条件判断 |
| 9 | 求极差 | P5729 | 循环求最大最小值 |
| 10 | [NOIP2002 普及组] 过河卒 | P1002 | 循环 + 二维数组(难度稍高) |
建议:从简单的累加、累乘开始,逐步挑战循环嵌套和复杂逻辑。
6. 总结
| 循环类型 | 适用场景 | 特点 |
|---|---|---|
while |
循环次数未知,需先判断条件 | 可能一次都不执行 |
do-while |
至少需要执行一次的场景(如菜单) | 先执行后判断 |
for |
循环次数已知(如遍历数组、计数) | 结构清晰,推荐优先使用 |
| 循环嵌套 | 处理二维数据、打印图形、穷举组合 | 注意内外层关系,总次数为乘积 |
break |
提前退出循环(如找到目标后) | 只跳出当前最内层循环 |
continue |
跳过本次循环的剩余部分,继续下一次 | 不跳出循环 |
核心技巧:
- 避免死循环:确保循环条件最终为假。
- 注意循环变量的边界:
<=还是<要仔细。 - 嵌套循环中,内层循环的循环变量不要与外层冲突。
- 能用
for尽量用for,可读性更好。
教练寄语:循环是编程中最强大的结构之一。请务必多写代码,尤其是课后练习。当你能够熟练使用循环解决“累加、累乘、枚举、模拟”等问题时,你已经掌握了程序设计的核心能力。
参考资料
- 【书籍】《信息学奥赛一本通》第3章:循环结构程序设计
- 【书籍】《C++ Primer Plus》第5章:循环和关系表达式
- 【在线资源】OI Wiki - 循环结构