VieTopikKhoá học
  • Games
  • Cá nhân
Tải app
© 2026 VieTopikChính sách bảo mậtĐiều khoản sử dụngCài appEnglish
  • Trang chủ
  • Học
  • Luyện thi
  • Cẩm nang
  • Games
  • Cá nhân
Cấu trúc dữ liệu và giải thuậtĐo độ hiệu quả
Bài 1/18
6 phút

Big-O

Bình luận
Nội dung bài · 6 mục
  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Vòng lặp lồng nhau
  4. 4.Thử ngay
  5. 5.Lỗi hay gặp
  6. 6.Tóm tắt

Cửa hàng có 5 sản phẩm thì cách tìm nào cũng nhanh. Lên 5 triệu sản phẩm, có cách vẫn trả lời ngay, có cách chạy mãi không xong. Big-O cho bạn biết trước một cách giải chậm đi thế nào khi dữ liệu lớn lên.

Khái niệm

📈 Big-O: cách mô tả số bước của một thuật toán tăng thế nào khi số phần tử n tăng, bỏ qua các hằng số.

Big-O không đo giây, vì mỗi máy chạy nhanh chậm khác nhau. Nó đếm số bước và chỉ xem số bước tăng theo kiểu nào: dữ liệu gấp đôi thì số bước gấp đôi, gấp bốn, hay gần như không đổi.

Big-O Đọc là Ví dụ 1.000 phần tử
O(1) hằng số list[2], dict[key] (trung bình) 1 bước
O(log n) logarit tìm nhị phân trên dãy đã sắp xếp ~10 bước
O(n) tuyến tính duyệt list tìm một tên 1.000 bước
O(n log n) n log n merge sort ~10.000 bước
O(n²) bình phương hai vòng lặp lồng nhau 1.000.000 bước

Ví dụ

List<string> names = new List<string>
{
    "Bút bi", "Vở", "Balo", "Thước", "Máy tính"
};

// O(1): lấy theo vị trí, luôn chỉ một bước
Console.WriteLine(names[2]);   // Balo

// O(n): tìm theo tên, xấu nhất phải xem hết list
int steps = 0;
foreach (string name in names)
{
    steps++;
    if (name == "Máy tính")
    {
        break;
    }
}
Console.WriteLine(steps);   // 5
  • names[2] nhảy thẳng tới ô thứ ba, không cần nhìn các ô khác.
  • Tìm "Máy tính" phải so từng tên từ đầu. List 5 triệu tên thì xấu nhất là 5 triệu lần so.
  • Big-O thường tính theo trường hợp xấu nhất: tên cần tìm nằm cuối, hoặc không có. Chỗ nào ghi "trung bình" là nói trường hợp thường gặp.

Vòng lặp lồng nhau

Vòng ngoài chạy n lần. Mỗi lần đó, vòng trong lại chạy n lần, nên tổng cộng là n × n bước: O(n²).

Console.WriteLine(CountSteps(10));   // 100

int CountSteps(int n)
{
    int steps = 0;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            steps++;
        }
    }
    return steps;
}

▶ Mô phỏng: Đếm bước của hai vòng lặp lồng nhau

Console.WriteLine(CountSteps(4));

int CountSteps(int n)
{
    int steps = 0;
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < n; j++)
        {
            steps++;
        }
    }
    return steps;
}
Xem từng bước
  1. i = 0: vòng trong chạy lại từ j = 0. steps = 1.
  2. i = 0, j = 1: steps = 2.
  3. i = 0, j = 2: steps = 3.
  4. i = 0, j = 3: steps = 4.
  5. i = 1: vòng trong chạy lại từ j = 0. steps = 5.
  6. i = 1, j = 1: steps = 6.
  7. i = 1, j = 2: steps = 7.
  8. i = 1, j = 3: steps = 8.
  9. i = 2: vòng trong chạy lại từ j = 0. steps = 9.
  10. i = 2, j = 1: steps = 10.
  11. i = 2, j = 2: steps = 11.
  12. i = 2, j = 3: steps = 12.
  13. i = 3: vòng trong chạy lại từ j = 0. steps = 13.
  14. i = 3, j = 1: steps = 14.
  15. i = 3, j = 2: steps = 15.
  16. i = 3, j = 3: steps = 16.
  17. Trả về 16 = 4 × 4. Gấp đôi n thì số bước gấp bốn: O(n²).
  18. In 16. Thử đổi n ở ô "Tự thử" để thấy số bước tăng theo n × n.

Thử ngay

Thêm hai dòng sau vào dưới dòng gọi CountSteps(10):

Console.WriteLine(CountSteps(100));
Console.WriteLine(CountSteps(1000));

Đoán trước khi chạy: mỗi lượt n tăng 10 lần, từ 10 lên 100 rồi 1000. Số bước tăng bao nhiêu lần?

Xem kết quả
100
10000
1000000

Mỗi lượt tăng 100 lần, vì n tăng 10 lần thì n × n tăng 10 × 10 lần. Với O(n²), dữ liệu lớn gấp 10 là chờ lâu gấp 100.

Lỗi hay gặp

Gọi Contains của List trong vòng lặp. Code chỉ có một vòng lặp, nhưng mỗi lần gọi, Contains lại duyệt cả list, nên tổng cộng là O(n²).

// SAI — O(n²): Contains duyệt lại list mỗi vòng
List<string> seen = new List<string>();
foreach (string name in names)
{
    if (seen.Contains(name))
    {
        Console.WriteLine("Trùng: " + name);
    }
    seen.Add(name);
}
// ĐÚNG — O(n): ContainsKey của Dictionary là O(1)
Dictionary<string, bool> seen =
    new Dictionary<string, bool>();
foreach (string name in names)
{
    if (seen.ContainsKey(name))
    {
        Console.WriteLine("Trùng: " + name);
    }
    seen[name] = true;
}

Vì sao ContainsKey chỉ tốn một bước là chuyện của chương Bảng băm.

Tóm tắt

  • Big-O mô tả số bước tăng thế nào khi dữ liệu tăng, không đo giây.
  • Lấy theo vị trí là O(1), duyệt tìm là O(n), hai vòng lồng nhau là O(n²).
  • Thường tính theo trường hợp xấu nhất và bỏ qua hằng số.
  • Cẩn thận với method có vòng lặp ẩn bên trong, như List.Contains.
Đệ quy

Bình luận

Đang tải bình luận…

Nội dung bài

  1. 1.Khái niệm
  2. 2.Ví dụ
  3. 3.Vòng lặp lồng nhau
  4. 4.Thử ngay
  5. 5.Lỗi hay gặp
  6. 6.Tóm tắt