CC++ & Algorithm

循环嵌套

困难0
语言版本:C++
概述:循环里面再套循环,就像日历有月份和日期。

循环嵌套:就像日历里有月份和日期

有时候一个循环不够,需要在一个循环里面再放一个循环,这就是循环嵌套。简单说,就是一个循环的“身体”里,又写了一个循环。比如我们看日历:外面是大循环——月份从1到12;里面是小循环——每个月的天数从1号到28或30或31号。用循环嵌套可以很方便地处理这种“两层结构”的问题。

生活中还有很多这样的例子:

  • 课程表:外面是星期几(周一至周五),里面是每天的课节(第1节、第2节……)
  • 食堂排队:外面是年级(一年级、二年级……),里面是每个年级的同学依次打饭
  • 游戏地图:外面是行(从上到下),里面是列(从左到右),每个格子放一个角色

什么是循环嵌套?

循环嵌套就是在一个循环的代码块里,再写一个完整的循环。外层循环每执行一次,内层循环就要从头到尾完整地执行一遍。就像这样:

for 外层变量 in 外层范围:   # 外层循环
    # 外层循环的代码
    for 内层变量 in 内层范围:  # 内层循环(嵌套)
        # 内层循环的代码
    # 外层循环还可能有些代码(比如换行)

注意:内层循环必须完全在外层循环的内部,并且缩进要正确。缩进错了,内层循环就可能跑到外面去了,结果就不是嵌套了。

为什么需要循环嵌套?

因为有时候我们遇到的不是“一条直线”上的重复,而是“表格”或“网格”式的重复。比如:

  • 要打印一个 5 行 5 列的星星方阵,需要重复行(外层循环),每行又要重复打印列(内层循环)
  • 要遍历一个二维列表(如考试成绩表),需要先遍历行,再遍历每行里的列
  • 要画出各种图形(三角形、菱形),每行的星星数量不同,需要用内层循环控制数量

生活中的例子:打印一个小星星三角形

想象你要用星星拼出一个直角三角形:

*
**
***
****
*****

第1行1个星,第2行2个星……第5行5个星。这就可以用循环嵌套:外层循环控制行数(1到5),内层循环控制每行要打印的星星个数(等于当前行号)。

rows = 5            # 总行数
for i in range(1, rows + 1):    # 外层循环 i 从1到5,代表行号
    for j in range(i):          # 内层循环 j 从0到i-1,共i次,打印i个星
        print('*', end='')      # end='' 表示不换行,连续打印星
    print()                     # 每行结束后换行

运行结果:

*
**
***
****
*****

如果把这个三角形反过来(倒三角),只需要让外层循环从大到小,或者调整内层循环的范围。试试把 range(1, rows+1) 改成 range(rows, 0, -1) 看看效果。


最经典的例子:九九乘法表

上面已经提到过九九乘法表,我们再来仔细分析一遍它的工作过程。

for i in range(1, 10):           # 外层循环 i 从1到9,代表行号(也是第一个乘数)
    for j in range(1, i + 1):    # 内层循环 j 从1到i,每行的列数等于当前行号
        product = i * j          # 计算结果
        print(f"{j}x{i}={product}", end="\t")  # 打印算式,用制表符分隔
    print()                      # 每一行结束后换行

一步步拆解(以 i=3 为例)

  • 外层 i=3,进入内层:
    • j=1: 打印 1x3=3,不换行
    • j=2: 打印 2x3=6,不换行
    • j=3: 打印 3x3=9,不换行
  • 内层结束,执行 print() 换行,然后继续外层 i=4

这样,每行打印的算式个数正好等于行号,结果就是等腰直角三角形的乘法表。

注意:这里内层循环的范围 range(1, i+1) 是动态变化的,因为每行的列数不同,外层变量 i 控制着内层循环的次数。


循环嵌套还可以干什么?

1. 处理二维列表

假设有一个成绩表,每行是一个同学,每列是各科成绩:

# 成绩表:行代表同学,列代表 [语文, 数学, 英语]
scores = [
    [90, 85, 88],   # 小明
    [78, 92, 80],   # 小红
    [95, 89, 91]    # 小刚
]

for row in scores:                  # 外层循环:遍历每个同学(每一行)
    total = 0                       # 这个同学的总分
    for score in row:               # 内层循环:遍历该同学的各科成绩
        total += score
    print(f"总分: {total}")

2. 画更复杂的图案

比如打印空心正方形:

n = 5                               # 边长
for i in range(n):                  # 外层循环:行
    for j in range(n):              # 内层循环:列
        if i == 0 or i == n-1 or j == 0 or j == n-1:  # 在第一行、最后一行、第一列、最后一列打印*
            print('*', end=' ')
        else:
            print(' ', end=' ')     # 其他位置打印空格
    print()                         # 每行结束换行

新手容易犯的错误

错误1:缩进错误——内层循环跑到了外面

for i in range(3):
    print("外层", i)
for j in range(2):          # 这个缩进不对!它和上面for是平级的,不是嵌套
    print("内层", j)

这样只会先执行外层循环3次,再执行内层循环2次,不是嵌套效果。正确写法是内层循环缩进到外层循环内部。

错误2:忘记重置内层变量或计数器

有时候我们需要在内层循环开始前重置某个变量,比如累加总分:

for row in scores:
    total = 0                # 重要:每处理一个新行,先清零
    for score in row:
        total += score
    print(total)

如果 total = 0 放在了外层循环外面,那么它只会清零一次,之后每个同学的总分会累加前面的结果,就错了。

错误3:内外层循环变量名混用

for i in range(5):
    for i in range(3):      # 内外层用了同一个变量名 i
        print(i)

这样内层循环会改变外层 i 的值,导致外层循环失控。建议内层用不同的变量名,比如 jk

错误4:无限循环(当用while时)

i = 1
while i <= 3:
    j = 1
    while j <= 3:
        print(i, j)
        j += 1              # 别忘了更新j,否则内层无限循环
    i += 1                  # 别忘了更新i

while 嵌套时一定要小心更新循环变量的语句,否则容易死循环。


完整可运行示例:打印数字金字塔

下面是一个完整的程序,它打印一个数字金字塔(每行显示从1到行号的数字),并且加了注释:

# 打印数字金字塔,共6行
rows = 6                              # 总行数

for i in range(1, rows + 1):          # 外层循环:行号 i 从1到6
    # 1) 打印空格,让金字塔居中
    for space in range(rows - i):     # 内层循环1:打印空格
        print(' ', end=' ')           # 每行前面空 (rows-i) 个空格
    # 2) 打印数字:从1递增到i
    for num in range(1, i + 1):       # 内层循环2:打印递增数字
        print(num, end=' ')           # 不换行,空格分隔
    # 3) 打印数字:从i-1递减到1
    for num in range(i - 1, 0, -1):   # 内层循环3:打印递减数字
        print(num, end=' ')
    print()                           # 换行,准备下一行

运行结果(金字塔形状):

          1 
        1 2 1 
      1 2 3 2 1 
    1 2 3 4 3 2 1 
  1 2 3 4 5 4 3 2 1 
1 2 3 4 5 6 5 4 3 2 1 

相关知识点指引

  • for 循环:循环嵌套的基础,要熟练掌握 range() 的用法(起始、结束、步长)
  • while 循环:也可以用 while 实现嵌套,但要小心无限循环
  • 列表和二维列表:循环嵌套经常用来遍历二维列表,比如矩阵、成绩表
  • 字符串格式化:如 f"{j}x{i}={product}",让输出更整齐
  • break 和 continue:可以在循环嵌套中使用,但要注意它们只作用于当前所在的循环(最内层)

尝试自己动手改一改上面的例子:把数字金字塔改成字母金字塔,或者用循环嵌套画一个棋盘格。多练几次,你就会发现循环嵌套其实就像玩俄罗斯套娃——一层一层,整整齐齐。

例题精讲

1单选题

执行以下代码后,变量 s 的值是多少? s = 0 for i in range(3): for j in range(i+1): s += 1 print(s)

A3
B6
C9
D10
2判断题

执行以下代码会输出 10 个星号(*)。 for i in range(5): for j in range(2): print('*', end='')

3填空题
以下代码使用循环嵌套输出一个 3 行 4 列的矩形,每行由4个星号组成。请填写缺失的代码。
for i in range(3):
    for j in range(___):
        print('*', end='')
    print()
4单选题

关于以下代码,说法正确的是? count = 0 for i in range(1, 6): for j in range(1, i): count += 1 print(count)

A输出 5
B输出 10
C输出 15
D输出 20
5填空题
以下代码用循环嵌套打印一个直角三角形(第 i 行有 i 个星号,i从1开始)。请补充内层循环的 range 参数。
for i in range(1, 6):
    for j in range(___):
        print('*', end='')
    print()