循环结构

建议先阅读: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;
}

对原生数组,编译器使用指针;对 STL 容器,调用 begin()/end() 方法。


语法

三种循环

// 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);

break 和 continue

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

break 只能跳出最内层循环。多层跳出需使用标志变量。

range-based for (C++11)

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 << ' ';
}

对容器首选 const auto& 遍历,既避免拷贝又能保护原数据。

死循环

while (true) {
    if (exit_condition) break;
}
// 等价于
for (;;) {
    if (exit_condition) break;
}

实践

常见循环模式:

模式代码
累加sum += arr[i];
计数if (cond) count++;
查找if (arr[i] == target) { found = true; break; }
最值if (arr[i] > max) max = arr[i];

判断素数(优化到 sqrt):

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;
}

i * i <= ni <= sqrt(n) 更高效——免去浮点运算开销。注意 i * i 可能 int 溢出,大规模可改用 long long i

力扣:
力扣: 简单遍历题 (遍历+最值)
力扣: 分类统计题 (循环+分类统计)
力扣: while 循环计数题 (while 循环)
力扣: 嵌套循环题 (嵌套循环)

AI 自检提示:询问 AI “编译器通常对循环做哪些优化,为什么 i*i 比 sqrt(n) 更高效”。