3.4.4 嵌套循环
为了实现复杂的算法,控制结构可以相互嵌套,即一个控制结构处于另一个控制结构的 内部。前面我们见过 if 结构的嵌套,现在我们讨论循环的嵌套。
先考虑“一维”数据结构——由简单数据值构成的列表,为了遍历列表以处理其中数据, 我们需要一个循环。例如用一个循环来计算列表中所有数据之和:
>>> a = [1,2,3,4,5]
>>> sum = 0
>>> for i in a:
sum = sum + i
>>> print sum
15
但是一个循环不足以解决“二维”数据结构——如矩阵。第 2 章中介绍过,编程语言中 用“列表的列表”来表示矩阵。用一个循环可以每次取列表中的一个值来处理,但这个值本 身又是一个列表,因此又需要一个循环来遍历之。这样我们就得到一个嵌套的循环结构来处 理二维数据结构,如下面的代码所演示的那样:
>>> a = [[11,12,13,14],[21,22,23,24],[31,32,33,34]]
>>> sum = 0
>>> for i in a:
for j in i:
sum = sum + j
>>> print sum
270
可见,为了遍历矩阵,需要由外循环和内循环嵌套来完成:外循环负责对所有的行进行 遍历,而内循环负责对当前行的每一列进行遍历。首先由外循环取一行,再由内循环处理这 一行;当内循环处理完一行,控制又转到外循环去取下一行。例如,外循环控制变量 i 取第 一行[11,12,13,14]时,内循环控制变量 j 取遍 i 中的 11、12、13 和 14 进行处理,处理完毕后 i 再取第二行进行处理,依次类推。
当然,二维数据结构不一定都像矩阵这么整齐,每一行数据可能有长有短,因此在用嵌 套循环来遍历所有数据时,内循环的循环次数常常要根据外循环的循环控制变量值做相应调 整。作为例子,请看下面这个打印乘法口诀表的嵌套循环:
>>> for i in range(1,10):
for j in range(1,i+1):
print "%dx%d=%-2d" % (j,i,j*i),
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81
这段代码虽然很简单,却展示了嵌套循环编程中常用的两个技巧。首先,内循环的循环 次数(由 range(1,i+1)决定)依赖于外循环的循环控制变量 i,因为对 i=1 只有一个乘式,对 i=2 有两个乘式,…,对 i=9 有九个乘式。其次,为了将每个 i 值所产生的乘式放在同一行上, 且不同 i 值的乘式放在不同行上,我们在外循环的循环体中与内循环 for 语句并列写了一条 print 语句,以便每当内循环结束就换一次行;而在内循环的循环体中,print 语句的最后是用 逗号结尾的,表示每次循环期间不换行。
设计嵌套循环时,一般先设计外循环,这时并不考虑内循环要做的事。当把外循环的结 构搭建好之后,再去设计内循环的任务,这时又不需要考虑外循环。最后将内外两个循环的 代码融合在一起,就得到了完整的嵌套循环代码。
和两重嵌套循环类似,嵌套循环还可以由三重循环构成,用于处理三维数据结构。依此 类推,n 重嵌套循环可用于处理 n 维的数据结构。
3.4.3 节中介绍的 break 语句只能跳出包围它的那一层循环。在嵌套循环结构的情况下, 一条 break 语句虽然跳出了本层循环,但跳不出外层循环,因此控制仍然可能处于某个循环 体中。例如,我们改写打印乘法口诀表的程序,使得一部分乘式不显示。代码如下:
>>> for i in range(1,10):
for j in range(1,i+1):
if j > 4: break
print "%dx%d=%-2d" % (j,i,j*i),
1x1=1
1x2=2 2x2=4
1x3=3 2x3=6 3x3=9
1x4=4 2x4=8 3x4=12 4x4=16
1x5=5 2x5=10 3x5=15 4x5=20
1x6=6 2x6=12 3x6=18 4x6=24
1x7=7 2x7=14 3x7=21 4x7=28
1x8=8 2x8=16 3x8=24 4x8=32
1x9=9 2x9=18 3x9=27 4x9=36
从上面的代码和结果可以看出,对于内循环所处理的每一行,j>4 的乘式都被 break 跳过了, 但是外循环仍能继续执行。