Vòng lặp lồng nhau

Khái niệm

Vòng lặp lồng nhau là cấu trúc trong đó một vòng lặp được đặt bên trong vòng lặp khác. Cách tổ chức này thường dùng để duyệt bảng hai chiều, ma trận hoặc tạo các mẫu lặp theo hàng và cột.

Ví dụ in bảng nhân 3 x 3

for row in range(1, 4):
    for column in range(1, 4):
        print(row * column, end=" ")
    print()
program NestedLoopDemo;

var
  rowIndex, columnIndex: Integer;

begin
  for rowIndex := 1 to 3 do
  begin
    for columnIndex := 1 to 3 do
      Write(rowIndex * columnIndex, ' ');
    Writeln;
  end;
end.
#include <stdio.h>

int main(void) {
    int rowIndex;
    int columnIndex;

    for (rowIndex = 1; rowIndex <= 3; rowIndex++) {
        for (columnIndex = 1; columnIndex <= 3; columnIndex++) {
            printf("%d ", rowIndex * columnIndex);
        }
        printf("\n");
    }

    return 0;
}
#include <iostream>
using namespace std;

int main() {
    for (int row = 1; row <= 3; row++) {
        for (int col = 1; col <= 3; col++) {
            cout << row * col << " ";
        }
        cout << endl;
    }

    return 0;
}
for (int row = 1; row <= 3; row++)
{
    for (int col = 1; col <= 3; col++)
    {
        Console.Write(row * col + " ");
    }
    Console.WriteLine();
}
for (let row = 1; row <= 3; row++) {
    let line = "";
    for (let col = 1; col <= 3; col++) {
        line += (row * col) + " ";
    }
    console.log(line.trim());
}
for (let row: number = 1; row <= 3; row++) {
    let line: string = "";
    for (let col: number = 1; col <= 3; col++) {
        line += (row * col) + " ";
    }
    console.log(line.trim());
}
package main

import "fmt"

func main() {
    for row := 1; row <= 3; row++ {
        for col := 1; col <= 3; col++ {
            fmt.Printf("%d ", row*col)
        }
        fmt.Println()
    }
}
fn main() {
    for row in 1..=3 {
        for col in 1..=3 {
            print!("{} ", row * col);
        }
        println!();
    }
}

Điều cần lưu ý

  • Vòng lặp trong chạy trọn vẹn cho mỗi lần lặp của vòng ngoài.
  • Số lần thực hiện tăng nhanh khi số tầng lồng nhau tăng lên.
  • Tên biến điều khiển nên đủ rõ để phân biệt vai trò từng tầng lặp.

Kết luận

Vòng lặp lồng nhau rất mạnh nhưng cũng dễ làm tăng chi phí tính toán. Vì vậy nên cân nhắc số tầng lặp và số phần tử cần duyệt trước khi triển khai. Trong mục Thuật toán, các thuật toán O(n²) như sắp xếp nổi bọsắp xếp chọn chính là ứng dụng điển hình của vòng lặp lồng nhau.

Ghi chú theo ngôn ngữ

Thông tin</div>

Python không có cú pháp thoát vòng lặp có nhãn. Để thoát vòng ngoài từ bên trong vòng trong, thường dùng biến cờ (found = True; break) hoặc đặt toàn bộ vòng lặp lồng nhau vào một hàm rồi dùng return.

Pascal dùng begin...end bắt buộc cho thân vòng lặp có nhiều câu lệnh. Trong vòng lặp lồng nhau, mỗi tầng cần cặp begin...end riêng. Pascal không có break có nhãn — cần dùng biến cờ hoặc goto để thoát nhiều tầng.

break trong C chỉ thoát vòng lặp trong cùng. Để thoát vòng ngoài, cần dùng biến cờ hoặc goto. C không hỗ trợ nhãn vòng lặp.

C++ có cùng giới hạn với C: break chỉ thoát vòng trong cùng. Thay vì dùng goto, cách C++ khuyến dùng là tách vòng lặp lồng nhau ra hàm riêng và return khi cần thoát.

C# không hỗ trợ break có nhãn, nhưng có goto an toàn hơn C/C++ (chỉ cho phép nhảy tới nhãn trong cùng hàm). Cách khuyến dùng là tách logic lồng nhau thành hàm riêng.

JavaScript hỗ trợ nhãn vòng lặp (labeled statement): outer: for (...) rồi break outer; trong vòng trong để thoát cả hai. Tuy nhiên, tính năng này ít dùng và có thể gây khó đọc.

TypeScript hỗ trợ nhãn vòng lặp giống JavaScript. Ngoài ra, TypeScript khuyến khích tách logic phức tạp thành hàm có kiểu rõ ràng, giúp mã an toàn và dễ hiểu hơn.

Go hỗ trợ nhãn vòng lặp thực sự: outer: trước vòng ngoài, rồi break outer trong vòng trong. Đây là cơ chế sạch hơn so với biến cờ và được dùng trong mã Go thực tế.

Rust hỗ trợ nhãn vòng lặp với cú pháp 'outer: loop { ... break 'outer; }. Nhãn bắt đầu bằng dấu nháy đơn. break 'label thoát vòng lặp được chỉ định, continue 'label tiếp tục vòng lặp đó.

Bình luận