Sắp xếp trộn
Định nghĩa
Sắp xếp trộn (merge sort) là một thuật toán sắp xếp ổn định, hiệu quả dựa trên so sánh.
Tính chất
Sắp xếp trộn dựa trên tư tưởng chia để trị, chia mảng thành các đoạn nhỏ rồi hợp lại, có độ phức tạp thời gian tốt nhất, xấu nhất và trung bình đều là \(\Theta (n \log n)\), độ phức tạp bộ nhớ là \(\Theta (n)\).
Sắp xếp trộn có thể chỉ dùng \(\Theta (1)\) bộ nhớ phụ, nhưng thường để tiện lợi sẽ dùng một mảng phụ có độ dài bằng mảng gốc.
Quy trình
Hợp mảng (merge)
Phần cốt lõi của merge sort là quá trình hợp hai mảng: hợp hai mảng đã sắp xếp a[i] và b[j] thành một mảng đã sắp xếp c[k].
Duyệt từ trái sang phải các phần tử a[i] và b[j], chọn giá trị nhỏ nhất đưa vào c[k]; lặp lại cho đến khi một trong hai mảng hết phần tử, sau đó đưa nốt phần còn lại của mảng kia vào c[k].
Để đảm bảo tính ổn định, khi hai phần tử đầu bằng nhau (a[i] <= b[j]), phải ưu tiên lấy phần tử ở mảng trước.
Cài đặt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Có thể dùng hàm merge trong <algorithm>, cách dùng giống như kiểu con trỏ ở trên.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
Cài đặt merge sort bằng chia để trị
-
Khi mảng chỉ còn 1 phần tử, nó đã được sắp xếp, không cần chia nhỏ nữa.
-
Khi mảng có nhiều hơn 1 phần tử, chia thành hai đoạn, kiểm tra từng đoạn đã sắp xếp chưa (bước 1). Nếu chưa, tiếp tục chia nhỏ (bước 2), sau đó hợp lại.
Có thể chứng minh bằng quy nạp rằng quá trình này sẽ sắp xếp được mảng.
Để đảm bảo độ phức tạp, thường chia mảng thành hai đoạn gần bằng nhau (\(mid = \left\lfloor \dfrac{l + r}{2} \right\rfloor\)).
Cài đặt
Lưu ý các đoạn code dưới đây dùng các đoạn \([l, r)\), \([l, mid)\), \([mid, r)\).
1 2 3 4 5 6 7 8 9 10 11 | |
1 2 3 4 5 6 7 8 9 | |
Cài đặt merge sort bằng phương pháp tăng dần đoạn (bottom-up)
Khi mảng có độ dài 1, mỗi đoạn đã được sắp xếp.
Từ trái sang phải, hợp từng cặp đoạn độ dài 1 thành các đoạn độ dài \(\leq 2\) đã sắp xếp;
Tiếp tục hợp từng cặp đoạn độ dài \(\leq 2\) thành các đoạn độ dài \(\leq 4\) đã sắp xếp;
Tiếp tục hợp từng cặp đoạn độ dài \(\leq 4\) thành các đoạn độ dài \(\leq 8\) đã sắp xếp;
...
Lặp lại cho đến khi chỉ còn một đoạn, đó là mảng đã sắp xếp.
Tại sao là \(\le n\) mà không phải \(= n\)
Độ dài mảng có thể không phải là \(2^x\),nên đoạn cuối cùng có thể không đủ,có thể có đoạn lẻ.
Cài đặt
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | |
1 2 3 4 5 6 7 8 9 | |
Đếm số nghịch thế (inversion)
Xem thêm và code mẫu: Nghịch thế
Nghịch thế là các cặp \((i, j)\) với \(i < j\) và \(a_i > a_j\).
Sau khi sắp xếp, mảng không còn nghịch thế. Trong quá trình hợp mảng của merge sort, mỗi lần lấy phần tử đầu của đoạn sau làm giá trị nhỏ nhất, số phần tử còn lại ở đoạn trước chính là số nghịch thế bị loại bỏ; do đó merge sort đếm nghịch thế trong thời gian \(\Theta (n \log n)\). Ngoài ra, có thể dùng Fenwick tree hoặc segment tree để đếm nghịch thế với \(O(n \log n)\); xem chi tiết ở Fenwick tree. Code mẫu ở Nghịch thế.
Liên kết ngoài
Last updated on this page:, Update history
Found an error? Want to help improve? Edit this page on GitHub!
Contributors to this page:OI-wiki
All content on this page is provided under the terms of the CC BY-SA 4.0 and SATA license, additional terms may apply