CC++ & Algorithm

循环嵌套经典算法

较难5
语言版本:C++Python
概述:学习用循环嵌套解决常见问题,比如找素数、九九乘法表,锻炼逻辑思维。

循环嵌套,一个解决复杂问题的好帮手

你有没有遇到过这样的问题:需要反复做一件事,而这件事本身又需要重复好几次?比如:背一遍九九乘法表,里面每一行都要背1×1、1×2……这就是“重复中的重复”。在编程里,我们用循环嵌套来处理这种“大循环套小循环”的任务——外层循环控制大节奏,内层循环处理每个小细节。

下面我们就用两个经典案例来学习循环嵌套:打印九九乘法表,以及找出所有素数。这两个例子你肯定熟悉,但用代码写出来会特别有成就感!


1. 打印九九乘法表:先理解规律,再写出循环

九九乘法表有什么规律?

  • 第1行有1个式子:1×1
  • 第2行有2个式子:1×2、2×2
  • 第3行有3个式子:1×3、2×3、3×3
  • ……
  • 第9行有9个式子:1×9、2×9…9×9

你会发现:行数 i 从1到9,每一行内的列数 j 从1到 i。这不就是典型的“外层循环控制行,内层循环控制列”吗?而且内层循环的终点取决于外层循环的当前值。

代码写出来是这样的(注意变量名用英文单词,每行加了中文注释):

for i in range(1, 10):              # 外层循环,i 从1到9,代表行号(乘法表的第二个乘数)
    for j in range(1, i + 1):        # 内层循环,j 从1到i,代表第一个乘数
        # 用f-string格式化输出,比如"1*2=2",并用制表符\t让每列对齐
        print(f"{j}*{i}={i*j}", end="\t")
    print()                          # 一行结束后换行

输出结果(部分省略中间行,最后两行):

1*1=1	
1*2=2	2*2=4	
1*3=3	2*3=6	3*3=9	
...  (4~7行略)
1*8=8	2*8=16	3*8=24	4*8=32	5*8=40	6*8=48	7*8=56	8*8=64	
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个,第二天背2个,第三天背3个……外层循环是“天数”,内层循环是“当天要背的单词数量”。


2. 找出所有素数:用“试除法”加循环嵌套

什么是素数? 只能被1和它本身整除的数,比如2、3、5、7、11……1不是素数。
怎么判断一个数 n 是不是素数? 从2开始一直试到 n-1,看看有没有数能整除 n。如果有一个能整除,n 就不是素数;如果没有,n 就是素数。

如果我们要找100以内的所有素数,就需要对每个数(从2到100)做一次判断。每个判断又需要一个小循环(从2试到 n-1)。这就是“外层循环遍历候选数,内层循环做试除”。

代码实现(注意:内层循环每次都要重新假设这个数是素数):

for n in range(2, 101):              # 外层:检查2到100的每个数
    is_prime = True                   # 先假设当前数n是素数(“嫌疑人”是无辜的)
    for i in range(2, n):             # 内层:用2到n-1去试除
        if n % i == 0:                # 如果能被i整除,说明不是素数
            is_prime = False          # 推翻假设
            break                     # 不用再试后面更大的i了,直接退出内层循环
    if is_prime:                      # 如果内层循环结束后,is_prime仍然是True
        print(n, end=" ")             # 打印这个素数

输出(一行显示所有100以内的素数):
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97

生活小例子:你想从全班40位同学中找出所有“从未迟到的同学”。外层循环是逐个同学检查,内层循环是检查这个同学的每一天(假设有100天)是否迟到。一旦发现某一天迟到,就马上标记“不是从未迟到”,然后不用再看后面的日子了(break)。全部日子检查完还没发现迟到,就说明他是“从未迟到”的同学。


3. 循环嵌套的常见错误(新手最容易踩的坑)

错误1:内层循环的变量名和外层循环的变量名搞混

比如打印九九乘法表时,把内层循环写成 for j in range(1, i+1),却用了 j 的地方写成了 i。结果会输出一堆重复的数字。
解决方法:在外层用 irow,内层用 jcol,不要混用。

错误2:忘记重置“标志变量”

找素数时,is_prime = True 必须放在外层循环里面(每检查一个新数之前都要重新假设为真)。如果放在外层循环外面,判断完第一个数后 is_prime 变成了 False,后面所有数都不会被打印。
正确做法:把 is_prime = True 放在 for n in ... 的下一行。

错误3:内层循环的终点范围搞错

比如找素数时,内层循环写成 for i in range(2, n+1),这样包括 n本身,会导致 n%n==0,从而把素数也当成合数。
正确范围:应该是 range(2, n),即从2到n-1。

错误4:忘记使用 break 提前退出内层循环

虽然不写 break 程序也能正常运行,但会做很多无用功。比如检查100是不是素数,试到2发现能整除,其实已经可以下结论了,但如果不 break 还会继续试3、4……浪费时间。养成“找到证据就立刻停止”的好习惯。


4. 完整可运行的示例:找出100以内的素数并统计个数

下面是一个完整的程序,它不仅输出所有素数,还统计数量。你可以直接复制到 Python 中运行。

# 找出100以内的所有素数,并统计个数
count = 0                # 计数器,初始为0

for n in range(2, 101):  # 外层循环:从2到100
    is_prime = True       # 先假设当前数字是素数
    for i in range(2, n): # 内层循环:用2到n-1试除
        if n % i == 0:    # 如果能整除
            is_prime = False   # 不是素数
            break              # 立即退出内层循环
    if is_prime:               # 如果仍是素数
        print(n, end=" ")       # 打印这个素数,用空格分隔
        count = count + 1       # 计数器加1

print()                        # 换行
print("100以内的素数共有", count, "个")

输出结果(最后一行):

2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 
100以内的素数共有 25 个

小提示:如果把 range(2, 101) 改成 range(2, 1001),就能找出1000以内的所有素数。试一试吧!


5. 生活中的其他循环嵌套例子

例1:考试分数统计
老师要统计3个班级,每个班有40名同学的数学成绩。外层循环遍历班级,内层循环遍历班里的每个同学。
例2:课表安排
一周有5天,每天有8节课。外层循环是星期几,内层循环是第几节课。
例3:零食分发
妈妈买了3种零食,每种零食要分给2个孩子。外层循环是零食种类,内层循环是孩子编号。

这些都可以用循环嵌套来实现。你只要想清楚“哪个是外层的大循环,哪个是内层的小循环”。


6. 下一步可以学什么?

学会循环嵌套后,你就能挑战更多算法了,比如:

  • 冒泡排序:用两个循环给数字排队(外层控制轮数,内层控制比较次数)。
  • 百钱百鸡:中国古代的数学问题,用循环嵌套找所有可能解。
  • 图案打印:打印菱形、空心三角形等(用循环嵌套控制空格和星号)。

此外,你还会经常用到 breakcontinue 来优化循环,以及 else 子句(循环正常结束才执行 else)。这些内容会让你的代码更高效、更聪明。

记住:循环嵌套的核心就是“先画大圈,再在小圈里做细活”。多敲几遍代码,让手指记住这种感觉,以后你也能自己设计算法解决新问题!

例题精讲

1单选题

以下代码执行后,共输出多少行内容? for i in range(1, 4): for j in range(1, i + 2): print(i, j)

A6行
B9行
C12行
D18行
2判断题

在嵌套循环中,break语句的作用是立即终止所有外层循环,使程序完全跳出整个循环结构。

3填空题
以下代码用于判断一个大于1的整数n是否为素数。请补全条件。
def is_prime(n):
    for i in range(2, n):
        if ___ :
            return False
    return True
4单选题

下列代码运行后,打印的图形形状是? for i in range(1, 6): for j in range(1, 6 - i + 1): print('*', end='') print()

A左对齐的直角三角形(右下角为直角)
B左对齐的直角三角形(左上角为直角)
C靠右的直角三角形(右上角为直角)
D等边三角形
5判断题

使用嵌套循环输出九九乘法表时,内层循环变量j的上限通常设置为外层循环变量i的值,即内层循环次数随外层增加而增加。