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:輸出西洋棋棋盤 (8x8)
就讓第一個任務——在螢幕上輸出經典的西洋棋棋盤,以黑白格表示(假設 「#」——黑格,「.」——白格)。使用巢狀 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