Ký hiệu Big-O và các lớp tăng trưởng
1. Tổng quan
Hai thuật toán cùng giải một bài toán. Ta không hỏi máy nào chạy nhanh hơn.
Ta hỏi chi phí tăng nhanh ra sao khi đầu vào lớn dần. Big-O là ngôn ngữ trả lời câu hỏi đó.
2. Nguồn gốc: Bachmann và ý tưởng bậc tăng trưởng
Paul Bachmann đưa ra ký hiệu O(n) năm 1894. Ý ông rất gọn: bậc tăng của chi phí không vượt bậc của n.
Thay vì đếm từng phép tính, ta nhìn hình dạng đường cong. Thuật toán A tốn 100 bước, B tốn 10 bước trên mẫu thử.
Hai con số đó chưa nói lên tương lai. Nhưng nếu A tăng theo bình phương còn B tăng theo n, ta đoán được mọi kích thước đầu vào.
3. Định nghĩa chặn trên và cặp hằng số c, n0
Nói thuộc nghĩa là tỉ số bị chặn khi n lớn dần. Dù đầu vào phình to, không vượt một cách mất kiểm soát.
Ví dụ: thuộc . Tỉ số quanh quẩn gần 1000.
Khi n đủ lớn, đầu vào tăng gấp đôi thì chi phí tăng xấp xỉ gấp bốn. Đó là bản chất của bậc hai.
Định nghĩa chặt chẽ: nghĩa là có hằng số và ngưỡng sao cho mọi :
Ví dụ cụ thể: , , chọn và . Tại , vế trái 130 lớn hơn vế phải 120 nên chưa đạt.
Tại , hai vế cùng bằng 160. Từ trở đi, bất đẳng thức luôn đúng.
Hai điểm cần nhớ: chỉ xét n đủ lớn, và không phụ thuộc n. Giống như chỉ so tốc độ xe trên đường dài, không so lúc mới đề pa.
4. Chặn khít và chặn lỏng
Một hàm thuộc vô số lớp Big-O. Nhưng không phải lớp nào cũng hữu ích.
Ví dụ hàm : chọn , thì nó thuộc . Về mặt toán học, nó cũng thuộc , thậm chí .
Các phát biểu sau vẫn đúng nhưng vô dụng. Giống như nói đi chợ tốn ít hơn ngân sách cả nước.
Thực hành tốt là tìm chặn khít. Đó là lớp nhỏ nhất vẫn chặn được chi phí thật.
Ba ký hiệu đi cùng nhau:
| Ký hiệu | Nghĩa | Định nghĩa |
|---|---|---|
| Chặn trên | với mọi | |
| Chặn dưới | với mọi | |
| Chặn khít hai phía | Vừa vừa |
Ví dụ: thuộc . Nó thuộc nhưng không thuộc .
Trong tài liệu và phỏng vấn, người ta hay viết Big-O nhưng ý muốn nói chặn khít. Khi cần chính xác, hãy dùng .
5. Các quy tắc rút gọn khi làm việc với Big-O
Có năm quy tắc, cùng một tinh thần.
| Quy tắc | Nội dung | Kết quả |
|---|---|---|
| Vòng lặp đơn | Lặp n lần | |
| Vòng lặp lồng | Ngoài , trong | |
| Nối tiếp | Chạy pha rồi | |
| Số hạng trội | Cộng hai biểu thức | Giữ số hạng lớn hơn |
| Bỏ hằng số | Nhân với hằng số | Bỏ đi |
Ví dụ: thành . Ví dụ: chính là .
Một lỗi phổ biến: vẽ đồ thị vài điểm rồi kết luận Big-O. Hai đường cong có thể giao nhau nhiều lần. Vẽ chỉ giúp hình dung, chứng minh vẫn cần đại số.
6. Bốn lớp tăng trưởng nền tảng
Lớp hằng số tốn chi phí như nhau với mọi n. Ví dụ: đọc phần tử mảng theo vị trí, đẩy và bật ngăn xếp.
Đường chi phí của nó nằm ngang. Giống như lấy một món trong tủ, tủ to hay nhỏ cũng một tay.
Lớp logarit thu hẹp phạm vi mỗi bước. Ví dụ: tìm kiếm nhị phân loại bỏ một nửa mảng sau mỗi lần so sánh.
Giống như tra từ điển: mở giữa, bỏ nửa đầu, rồi lặp lại. Sau , đây là lớp tốt nhất: chỉ cần khoảng 20 bước.
Lớp tuyến tính tăng đều theo đầu vào. Ví dụ: duyệt danh sách để tính tổng hay tìm số nhỏ nhất.
Giống như điểm danh cả lớp: lớp đông gấp đôi thì mất giờ gấp đôi. Lớp bậc hai tăng theo bình phương đầu vào.
Ví dụ: hai vòng lặp lồng nhau, liệt kê mọi cặp trong danh sách. Số cặp bằng . Giống như mọi người trong lớp bắt tay nhau từng cặp.
Trong bốn lớp, kém nhất. Với , nó cần cỡ bước, quá chậm cho một lần chạy thông thường.
Hai lớp nữa gặp suốt khóa học:
- nằm giữa và . Đây là chi phí của các thuật toán sắp xếp hiệu quả như merge sort, heap sort.
- và là lớp mũ và giai thừa, ví dụ vét cạn mọi tập con hay mọi hoán vị. Chỉ dùng được khi rất nhỏ.
| 10 | 3.3 | 33 | 100 | 1024 |
| 1000 | 10 | quá lớn | ||
| 20 | quá lớn |
7. So sánh và đánh đổi
Big-O giúp dự báo trước khi cài đặt. Đo thực nghiệm giúp chọn sau khi cài đặt.
Cách khôn ngoan: dùng Big-O loại sớm thiết kế xấu. Rồi đo thực nghiệm trong nhóm ứng viên còn lại.
8. Cạm bẫy tư duy
Thứ nhất: lẫn hằng số với hình dạng tăng trưởng. Thuật toán với hằng số khổng lồ có thể thua trên dữ liệu thực tế.
Thứ hai: hài lòng với chặn lỏng đúng nhưng vô dụng. Thứ ba: đo vài điểm rồi gán nhãn Big-O vội vàng.
Thứ tư: quên ngưỡng . Với dữ liệu nhỏ, chọn thuật toán nào cũng gần như nhau.
9. Ứng dụng của tư duy này
Mỗi khi dữ liệu có thể phình to, hãy nghĩ Big-O trước. Nó cũng là ngôn ngữ chung để đọc tài liệu.
Hai người không cần cùng máy vẫn bàn được hiệu năng. Chỉ cần cùng nói Big-O.
✍️ Tự kiểm tra
Tự trả lời trước, rồi mở đáp án để đối chiếu.
Câu 1. thuộc lớp Big-O chặt nhất nào?
. Số hạng trội là , bỏ hằng số 5.
Câu 2. Chứng minh : chọn và nào?
Chọn , : với thì .
Câu 3. Hai vòng lặp lồng: ngoài chạy lần, trong chạy từ tới . Độ phức tạp?
Tổng số lần là , tức .
Câu 4. Vòng lặp for (i = 1; i < n; i *= 2) chạy bao nhiêu lần?
Khoảng lần, tức , vì nhân đôi mỗi vòng.
Câu 5. Thuật toán A tốn bước, B tốn bước. Với nào thì A nhanh hơn?
Khi . Với , B ít bước hơn dù có Big-O tệ hơn.
Tóm tắt
- Big-O mô tả hình dạng tăng trưởng của chi phí, bắt nguồn từ Bachmann năm 1894.
- Chặn trên dùng cặp và , cho phép bỏ hằng số và đầu vào nhỏ.
- Luôn tìm chặn khít thay vì chặn lỏng đúng nhưng vô dụng.
- Nắm năm quy tắc rút gọn và các lớp , , , , , .
- là chặn trên, là chặn dưới, là chặn khít.
- Dùng Big-O để loại sớm, đo thực nghiệm để chốt cuối.