循环结构(四)
多重循环:循环中的循环

从多名受试者多次测量,到阶乘和,理解“外层一轮,内层完整一轮”

上一次课我们解决了什么?

while

次数未知,但继续条件明确。

do-while

至少执行一次,再判断是否继续。

break/continue

提前结束整个循环,或跳过本轮。

今天的问题:一个循环不够时怎么办?

第1课时学习目标

知识目标

  • 理解多重循环的结构与执行顺序
  • 理解外层循环变量与内层循环变量的区别
  • 理解阶乘和问题中的嵌套循环模式

能力目标

  • 能判断问题中是否存在“两级重复关系”
  • 能跟踪 i、j 两层循环变量
  • 能分析内层循环初始化位置对结果的影响
4.4 / 多重循环
多名受试者,
每人多次测量
当问题中出现“人”和“每人的记录”两级重复,就需要嵌套循环。
外层循环内层循环二维数据

多名受试者 × 多次脉搏测量

受试者 第1次 第2次 第3次 第4次
A 72 73 71 72
B 68 69 70 68
C 80 78 79 80

外层重复

受试者 A → B → C

内层重复

每名受试者都要完成4次测量。

从表格到嵌套循环

for (patient = 1; patient <= 3; patient++) {
    for (measure = 1; measure <= 4; measure++) {
        scanf("%d", &pulse);
        printf("patient=%d, measure=%d\n", patient, measure);
    }
}
外层循环每执行一次,内层循环都要从头到尾完整执行一轮。

执行过程:谁先变?谁后变?

总次数 patient measure 含义
1 1 1 第1人第1次
2 1 2 第1人第2次
3 1 3 第1人第3次
4 1 4 第1人第4次
5 2 1 第2人第1次

内层循环变量变化更快;外层循环变量变化更慢。

🤖 AI 协作互动:双重循环变量跟踪

我正在学习 C 语言双重循环。外层 i 控制 3 名受试者,内层 j 控制每人 4 次脉搏测量。请帮我生成一个 i 和 j 变化的单步跟踪表格,展示当外层 i 进入下一轮时内层 j 是如何重置初始化的。

💡 课堂互动:同桌两人对照 AI 生成的变量跟踪表,口述外层一轮、内层跑完一整圈的过程。

多名受试者与嵌套循环

多名受试者与嵌套循环

交互演示:嵌套循环执行过程可视化

🔄 D04-03 · 嵌套循环执行过程可视化

本演示工具用于直观动态演示 C 语言双重嵌套循环 for(i=1;i<=3;i++) { for(j=1;j<=4;j++) {...} } 的单步执行逻辑:

  • 二维网格矩阵映射:右侧显示 3×4 网格,单步点击实时高亮当前坐标 (i, j)。
  • 循环状态联动:高亮左侧正在执行的代码行,并同步更新变量 i、j 的值与内层循环累计执行次数。
  • 内层轮次重置提示:每当内层循环跑满一轮(j=4)时,给出“内层循环完成一整圈,准备进入下一个 i”的醒目重置提醒。
教材例4-7
使用函数求阶乘和:
1! + 2! + ... + n!
把“求一个阶乘”的循环,放进“求多个阶乘并累加”的循环中。
阶乘函数嵌套循环

教材例4-7 题面描述

📋 题目要求

输入一个正整数 \(n\) (\(n \le 16\)),计算 \(1!+2!+3!+\ldots+n!\)。
要求定义和调用函数 fact(n) 计算 \(n\) 的阶乘,如果 \(n\) 是非负数,则该函数返回 \(n\) 的阶乘,否则返回 0。

先看一个小任务:求 n!

double fact(int n)
{
    int i;
    double result = 1;
    for (i = 1; i <= n; i++)
        result = result * i;
    return result;
}
这一层循环解决的是:从 1 乘到 n。

再看大任务:求 1!+2!+...+n!

sum = 0;
for (i = 1; i <= n; i++)
    sum = sum + fact(i);

外层循环

i = 1, 2, ..., n,依次求每个阶乘。

函数内部循环

fact(i) 内部再完成从1乘到i。

把函数内部展开,就是嵌套循环

sum = 0;
for (i = 1; i <= n; i++) {
    item = 1;
    for (j = 1; j <= i; j++) {
        item = item * j;
    }
    sum = sum + item;
}

外层负责“求第几个阶乘”,内层负责“把这个阶乘算出来”。

item = 1 应该放在哪里?

正确位置

for (i = 1; i <= n; i++) {
    item = 1;
    for (j = 1; j <= i; j++)
        item = item * j;
    sum = sum + item;
}

常见错误

item = 1;
for (i = 1; i <= n; i++) {
    for (j = 1; j <= i; j++)
        item = item * j;
    sum = sum + item;
}

为什么每次外层循环都要重新置 item=1?

求 1!

从1开始乘。

求 2!

仍然要从1重新开始乘。

求 3!

不能沿用上一次残留的 item。

内层循环使用的临时变量,往往需要在每次外层循环开始时重新初始化。

🤖 AI 协作互动:重置位置 Bug 诊断

计算 1! + 2! + ... + n! 时,如果我把内层阶乘变量重置语句 item = 1 错放在了外层 for 循环之前,计算结果会发生怎样的累乘错误?请用 n=3 为例推演数值变化。

💡 课堂互动:观察 AI 诊断出的“上一轮结果污染下一轮”典型错误,加深对内层变量初始化的记忆。

练习:内层循环总共执行多少次?

for (i = 1; i <= 100; i++) {
    for (j = 1; j <= i; j++) {
        printf("%d %d\n", i, j);
    }
}

前几轮

i=1 执行1次;i=2 执行2次;i=3 执行3次。

总次数

1+2+...+100=5050

🤖 AI 协作互动:高斯求和与复杂度分析

在两层嵌套循环中,外层 i 从 1 到 100,内层 j 从 1 到 i。如何利用高斯求和公式 1+2+...+n = n(n+1)/2 推导内层 printf 总共执行 5050 次?请用数学计算和 O(N^2) 时间复杂度做简要分析。

💡 课堂互动:引导学生体验从“代码单步计数”上升到“数学公式推导算法复杂度”。

本课小结:判断是否需要多重循环

是否有两级重复?
→
谁控制外层?
→
谁控制内层?
→
内层变量是否要重新初始化?
多重循环的核心不是“多写一个 for”,而是看清问题中存在几层重复关系。