CodeGym /Các khóa học /C# SELF /Vòng lặp lồng nhau và cách dùng chúng

Vòng lặp lồng nhau và cách dùng chúng

C# SELF
Mức độ , Bài học
Có sẵn

1. Giới thiệu

Bắt đầu bằng câu hỏi: Tại sao phải nhét một vòng lặp vào trong vòng lặp khác? Thật ra, dữ liệu hay bài toán của tụi mình thường không chỉ là một hàng dọc, mà có thể là bảng, lưới hoặc thậm chí là cấu trúc đa chiều. Ví dụ, bạn muốn in ra bảng cửu chương, duyệt qua mảng hai chiều hoặc tính toán giao điểm giữa tất cả các cặp phần tử. Lúc này, một vòng lặp là không đủ đâu — phải có vòng lặp trong vòng lặp.

Trong lập trình, vòng lặp lồng nhau giống như hai cái báo thức: cái ngoài kêu lên, bên trong lại có cái nữa kêu mỗi lần cái ngoài còn hoạt động. Nghĩa là, khi một vòng "bên ngoài" chạy một lượt, vòng "bên trong" sẽ chạy hết tất cả giá trị của nó (và cứ thế lặp lại cho mỗi lần lặp của vòng ngoài).

Ví dụ dễ hiểu là giờ và phút. Giờ là vòng ngoài từ 0 đến 23, phút là vòng trong từ 0 đến 59. Mỗi lần giờ thay đổi, vòng phút sẽ chạy hết tất cả giá trị của nó.

2. Cú pháp vòng lặp lồng nhau

Trong C#, cú pháp vòng lặp lồng nhau cũng giống như vòng lặp thường — bạn chỉ cần viết một vòng lặp bên trong thân của vòng lặp khác. Xem thử ví dụ với forwhile nhé:


for (int i = 0; i < 3; i++)
{
    for (int j = 0; j < 4; j++)
    {
        Console.Write($"{i},{j} ");
    }
    Console.WriteLine();
}
Vòng lặp lồng nhau for để in tọa độ

Ở đây, vòng ngoài điều khiển biến i (từ 0 đến 2), còn vòng trong là biến j (từ 0 đến 3). Với mỗi giá trị i, vòng trong sẽ chạy hết từ j=0 đến j=3. Nếu chạy đoạn code này, bạn sẽ thấy một bảng tọa độ rất gọn:

0,0 0,1 0,2 0,3 
1,0 1,1 1,2 1,3 
2,0 2,1 2,2 2,3 

Ví dụ tương tự với while:

int i = 0;
while (i < 3)
{
    int j = 0;
    while (j < 4)
    {
        Console.Write($"{i},{j} ");
        j++;
    }
    Console.WriteLine();
    i++;
}

Lưu ý: Trong mỗi lần chạy vòng ngoài, biến vòng trong (j) phải được khởi tạo lại, không thì bạn chỉ thấy một dòng thôi đó!

3. Ví dụ về vòng lặp lồng nhau

Ví dụ 1: In bàn cờ vua (8x8)

Bài đầu tiên: in ra bàn cờ vua cổ điển với ô đen và trắng (giả sử # là đen, _ là trắng). Làm bằng vòng lặp lồng nhau for nhé:


for (int row = 0; row < 8; row++)
{
    for (int col = 0; col < 8; col++)
    {
        if ((row + col) % 2 == 0)
            Console.Write("_");
        else
            Console.Write("#");
    }
    Console.WriteLine();
}
Vòng lặp lồng nhau để in bàn cờ vua

Kết quả:

_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_
_#_#_#_#
#_#_#_#_

Điểm quan trọng: Nhờ lồng nhau mà với mỗi dòng (row) ta duyệt hết tất cả các cột (col). Nếu không lồng nhau thì chỉ ra được một dòng hoặc một cột thôi, không thành bàn cờ đâu.

Ví dụ 2: Bảng cửu chương

Một ứng viên kinh điển cho vòng lặp lồng nhau! In bảng cửu chương 1-9 nhé:


for (int i = 1; i <= 9; i++)
{
    for (int j = 1; j <= 9; j++)
    {
        Console.Write($"{i * j,3} ");
    }
    Console.WriteLine();
}
Vòng lặp lồng nhau để in bảng cửu chương

Định dạng ${i * j,3} để bảng nhìn cho đẹp, thẳng hàng.

Kết quả:

   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. Vòng lặp lồng nhau và điều khiển chúng — mấy lưu ý

Ảnh hưởng của breakcontinue trong vòng lặp lồng nhau

Chỗ này nhiều bạn mới hay bị nhầm! Nếu bạn dùng break hoặc continue trong vòng lặp bên trong, nó chỉ ảnh hưởng vòng đó thôi. Vòng ngoài vẫn chạy bình thường.


for (int i = 0; i < 3; i++)
{
    for (int j = 0; j < 5; j++)
    {
        if (j == 3)
            break; // chỉ thoát vòng lặp bên trong thôi!
        Console.Write($"{i},{j} ");
    }
    Console.WriteLine();
}
break chỉ thoát vòng lặp bên trong

Kết quả:

0,0 0,1 0,2 
1,0 1,1 1,2 
2,0 2,1 2,2 

Nếu bạn muốn thoát luôn cả hai vòng lặp (ví dụ: tìm thấy kết quả đầu tiên trong bảng là dừng luôn), thường sẽ dùng biến cờ hoặc mẹo đặc biệt (ví dụ return — nếu mọi thứ nằm trong hàm).

5. Hình dung vòng lặp lồng nhau

Đôi khi khó mà "nhìn" được thứ tự thực thi của vòng lặp lồng nhau. Xem thử sơ đồ sau:

Hình dung vòng lặp lồng nhau

Dưới dạng bảng — tổng cộng có bao nhiêu lần lặp nếu i từ 1 đến 3, j từ 1 đến 4?

i j (duyệt cho mỗi i) Số lần lặp vòng trong
1 1, 2, 3, 4 4
2 1, 2, 3, 4 4
3 1, 2, 3, 4 4
Tổng: 3 × 4 = 12

6. Lỗi và bẫy khi dùng vòng lặp lồng nhau

Lỗi phổ biến là khởi tạo sai biến vòng trong. Ví dụ, khai báo nó ngoài vòng ngoài mà không reset lại mỗi lần. Kết quả là vòng trong có thể không chạy, hoặc chạy sai.

int j = 0;
for (int i = 0; i < 3; i++)
{
    while (j < 4) // Ôi! j có thể đã bằng 4 sau lần lặp đầu.
    {
        Console.Write($"{i},{j} ");
        j++;
    }
    Console.WriteLine();
}

Ở đây vòng lặp chỉ chạy một lần thôi. Nhớ khởi tạo biến vòng trong bên trong vòng ngoài nhé!

Ngoài ra, nếu lỡ viết hai vòng lặp lồng nhau mà dùng cùng tên biến, compiler sẽ báo lỗi: biến đã được khai báo rồi.


for (int i = 0; i < 3; i++)
{
    for (int i = 0; i < 3; i++)
    {
        Console.Write($"{i},{i} ");
    }
    Console.WriteLine();
}
1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Vòng lặp
Vòng lặp lồng nhau và cách sử dụng chúng
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION