循环结构

建议先阅读:07_条件语句

原理

循环的 CPU 视角

循环在底层由三部分组成:

  1. 循环计数器:存储在寄存器中
  2. 条件判断:cmp + 条件跳转(循环体 vs 退出)
  3. 循环体:重复执行的指令块

编译器对循环的优化手段:

  • 循环展开(loop unrolling):复制循环体减少分支判断次数
  • 循环向量化(SIMD):用 SSE/AVX 指令一次处理多个元素
  • 循环交换:调整嵌套循环顺序以优化缓存命中率
  • 循环合并/分裂:合并相同范围循环或拆分多功能循环

循环变量作用域与栈帧

for (int i = 0; ...)i 的作用域仅限于循环体内。循环体每次迭代不创建新的栈帧(与递归不同)——循环是单栈帧内的跳转,空间复杂度为 O(1)。递归每次调用创建新栈帧,空间复杂度为 O(n)。

range-based for 的实现

for (auto& x : arr) 被编译器展开为等价于:

for (auto it = begin(arr); it != end(arr); ++it) {
 auto& x = *it;
}
```cpp
对原生数组,编译器使用指针;对 STL 容器,调用 `begin()`/`end()` 方法。
 
---
 
## 语法
 
### 三种循环
 
```cpp
// for: 已知循环次数
for (int i = 0; i < n; i++) {
 std::cout << i << ' ';
}
 
// while: 条件驱动
while (x > 0) {
 x /= 2;
}
 
// do-while: 至少执行一次
do {
 std::cout << "输入正数: ";
 std::cin >> num;
} while (num <= 0);
```cpp
 
### breakcontinue
 
```cpp
for (int i = 0; i < 10; i++) {
 if (i == 3) continue; // 跳过 i=3
 if (i == 7) break; // i=7 时退出循环
 std::cout << i << ' ';
}
// 输出: 0 1 2 4 5 6
```cpp
 
`break` 只能跳出最内层循环。多层跳出需使用标志变量。
 
### range-based for (C++11)
 
```cpp
int arr[] = {1, 2, 3, 4, 5};
 
for (int x : arr) { // 值拷贝,不修改原数组
 std::cout << x << ' ';
}
 
for (int& x : arr) { // 引用,修改原数组
 x *= 2;
}
 
for (const auto& x : arr) { // 只读引用,避免拷贝
 std::cout << x << ' ';
}
```cpp
 
> 对容器首选 `const auto&` 遍历,既避免拷贝又能保护原数据。
 
### 死循环
 
```cpp
while (true) {
 if (exit_condition) break;
}
// 等价于
for (;;) {
 if (exit_condition) break;
}
```asm
 
---
 
## 实践
 
常见循环模式:
| 模式 | 代码 |
|------|------|
| 累加 | `sum += arr[i];` |
| 计数 | `if (cond) count++;` |
| 查找 | `if (arr[i] == target) { found = true; break; }` |
| 最值 | `if (arr[i] > max) max = arr[i];` |
 
判断素数(优化到 sqrt):
```cpp
bool isPrime(int n) {
 if (n < 2) return false;
 for (int i = 2; i * i <= n; i++) {
 if (n % i == 0) return false;
 }
 return true;
}
```cpp
 
> `i * i <= n` 比 `i <= sqrt(n)` 更高效——免去浮点运算开销。注意 `i * i` 可能 int 溢出,大规模可改用 `long long i`。
 
练习:
练习: 简单遍历题 (遍历+最值)
练习: 分类统计题 (循环+分类统计)
练习: while 循环计数题 (while 循环)
练习: 嵌套循环题 (嵌套循环)