Merge sort (Sắp xếp trộn)
Merge sort là thuật toán sắp xếp đầu tiên đưa ta vượt khỏi O(n^2). Bằng chiến lược
chia để trị (divide and conquer) — cắt đôi mảng, sắp từng nửa, rồi trộn (merge) hai
nửa đã sắp — nó đạt O(n log n) trong mọi trường hợp. Đổi lại, nó cần O(n) bộ nhớ phụ.
1. Trực quan: trộn hai chồng bài đã sắp
Tưởng tượng hai người bạn, mỗi người cầm một chồng bài đã sắp tăng dần. Nhiệm vụ của bạn: gộp chúng thành một chồng lớn cũng đã sắp. Cách làm rất tự nhiên — bạn chỉ nhìn lá trên cùng của hai chồng, lấy lá nhỏ hơn đặt xuống, rồi lặp lại. Vì mỗi chồng đã sắp sẵn, bạn không bao giờ phải nhìn lại phía sau.
Đó là phép merge. Merge sort = áp dụng ý tưởng này một cách đệ quy: cứ cắt đôi cho tới khi mỗi mảnh chỉ còn một phần tử (hiển nhiên đã sắp), rồi trộn ngược lên.
[5 3 8 1 9 2]
/ \
[5 3 8] [1 9 2] <- chia
/ \ / \
[5] [3 8] [1] [9 2]
/ \ / \
[3] [8] [9] [2]
\ / \ /
[3 8] [2 9] <- tron len
/ \
[3 5 8] [1 2 9]
\ /
[1 2 3 5 8 9] <- ket qua
2. Ý tưởng cốt lõi: chia, trị, trộn
Ba bư ớc kinh điển của chia để trị (xem lại bài 1.3.4):
- Chia (divide): cắt mảng làm đôi tại giữa.
- Trị (conquer): sắp xếp đệ quy mỗi nửa.
- Trộn (merge): gộp hai nửa đã sắp thành một mảng đã sắp — đây là phần "cơ bắp".
| Thuộc tính | Giá trị | Vì sao |
|---|---|---|
| Thời gian | O(n log n) | log n tầng chia, mỗi tầng trộn tốn O(n) |
| Bộ nhớ | O(n) | cần mảng phụ để trộn |
| Ổn định | Có | phần tử bằng nhau giữ nguyên thứ tự gốc |
3. Chạy debug: trộn [3, 8] với [1, 9]
Trái tim của merge sort là phép trộn. Bước qua để thấy ta lấy lá nhỏ hơn ở mỗi bước.