1. 引言
先问一个问题:为什么要把一个循环放进另一个循环?原因在于,我们的数据或任务往往不是一维的,而是例如表格、网格,甚至多维结构。假设你想打印乘法表、遍历二维数组,或统计所有元素对之间的交互/匹配。这时,一个循环显然不够——需要在循环中再套一个循环。
在编程中,嵌套循环就像两个闹钟:外层闹钟一响,内部又启动一个闹钟,并且只要外层还在运行,内层就会一遍遍地响。也就是说,在一次“外层”迭代期间,内层会完整地走完自己的全部迭代(并对外层的每一次迭代都重复这一过程)。
一个很好理解的例子是“小时与分钟”。小时——外层循环从 0 到 23,分钟——内层循环从 0 到 59。每当外层的小时变化一次,内层的分钟都会把自己的取值全部跑一遍。
2. 嵌套循环的语法
在 Java 中,嵌套循环的语法与普通循环并无区别——你只需在一个循环的主体内部再写一个循环。来看使用 for 和 while 的示例:
// 外层 for 循环
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++) // 内层 for 循环
{
System.out.print(i + "," + j + " ");
}
System.out.println(); // 内层循环结束后换行
}
这里外层循环控制变量 i(从 0 到 2),内层循环控制变量 j(从 0 到 3)。对于每个 i 的取值,内层循环都会完整地从 j == 0 跑到 j == 3。运行这段代码,你会看到整齐的坐标表:
0,0 0,1 0,2 0,3
1,0 1,1 1,2 1,3
2,0 2,1 2,2 2,3
使用 while 的等价示例:
int i = 0;
while (i < 3)
{
int j = 0;
while (j < 4)
{
System.out.print(i + "," + j + " ");
j++;
}
System.out.println();
i++;
}
请注意:在外层循环的每次迭代中,内层循环的变量(j)都必须重新初始化,否则你只会看到一行输出!
3. 嵌套循环的示例
示例 1:打印棋盘(8×8)
第一个任务——在屏幕上打印经典棋盘的黑白格(约定 “#” 为黑格,“.” 为白格)。我们用嵌套的 for 循环来实现:
for (int row = 0; row < 8; row++)
{
for (int col = 0; col < 8; col++)
{
// 如果行号与列号之和为偶数——输出白格,否则输出黑格
if ((row + col) % 2 == 0)
System.out.print("_");
else
System.out.print("#");
}
System.out.println(); // 每一行之后换行
}
输出:
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
要点:嵌套保证了对每一行(row)都会完整地遍历所有列(col)。没有嵌套就无法得到棋盘的二维结构——只能得到一行或一列。
示例 2:乘法表
这是最经典的嵌套循环应用之一!我们来打印 1–9 的乘法表:
for (int i = 1; i <= 9; i++)
{
for (int j = 1; j <= 9; j++)
{
System.out.print(i * j + "\t");
}
System.out.println();
}
这种格式 i * j + "\t" 会添加制表符,使表格看起来更整齐。
输出:
1 2 3 4 5 6 7 8 9
2 4 6 8 10 12 14 16 18
3 6 9 12 15 18 21 24 27
4 8 12 16 20 24 28 32 36
...
9 18 27 36 45 54 63 72 81
4. 嵌套循环与其控制——一些细节
关于 break 和 continue 在嵌套循环中的作用
很多新手会在这里踩坑!如果你在内层循环中使用 break 或 continue,它们只会影响该内层循环。外层循环不会受影响,仍会照常执行。
示例:仅提前退出内层循环
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 5; j++)
{
if (j == 3)
break; // 只跳出内层循环!
System.out.print(i + "," + j + " ");
}
System.out.println();
}
输出:
0,0 0,1 0,2
1,0 1,1 1,2
2,0 2,1 2,2
如果你需要同时退出两个嵌套循环(例如在表格中首次匹配成功后就立刻停止搜索),通常可以使用标志位或特殊手段(比如,如果一切都在函数内,则使用 return)。
5. 嵌套循环的可视化
有时很难直观地“看到”嵌套循环的执行顺序。来看下面的流程图:
从表格角度——当 i 从 1 到 3,j 从 1 到 4 时,总迭代次数是多少?
| i | j(对每个 i 依次取值) | 内层循环迭代次数 |
|---|---|---|
| 1 | 1, 2, 3, 4 | 4 |
| 2 | 1, 2, 3, 4 | 4 |
| 3 | 1, 2, 3, 4 | 4 |
| 合计:3 × 4 = 12 |
6. 使用嵌套循环的错误与陷阱
常见错误之一——错误地初始化内层循环的变量。比如,把它声明在外层循环之外,却没有在每一步重置。结果可能导致内层循环根本不执行,或者执行不正确。
int j = 0;
for (int i = 0; i < 3; i++)
{
while (j < 4) // 哎呀!第一次迭代后 j 可能已经等于 4。
{
System.out.print(i + "," + j + " ");
j++;
}
System.out.println();
}
这里循环只会运行一次。务必在外层循环内部初始化内层循环所用的变量!
另外,如果不小心在两个嵌套循环里使用了相同的变量(for (int i = 0; ...) { for (int i = 0; ...) { ... } }),编译器会报错:该变量已被定义。
GO TO FULL VERSION