Cho một mảng chỉ chứa các giá trị 0, 1 và 2. Yêu cầu sắp xếp mảng sao cho tất cả các 0 ở đầu, tiếp theo là 1, cuối cùng là 2. Phải sắp xếp tại chỗ (in-place) không dùng mảng phụ.
Chúng ta có thể giải quyết bài toán này bằng thuật toán Dutch National Flag (DNF) – thuật toán cờ Ba Lan, do Edsger Dijkstra đề xuất.
Ví dụ
Đầu vào 1: {2, 0, 0, 1, 2, 1}
Đầu ra: 0 0 1 1 2 2
Đầu vào 2: {0, 1, 1, 2, 1, 1, 0}
Đầu ra: 0 0 1 1 1 1 2
Ý tưởng thuật toán DNF
Thuật toán sử dụng 3 con trỏ để duyệt mảng và hoán đổi các phần tử cần thiết:
- low: bắt đầu tại đầu mảng (chỉ số 0) – vùng chứa các 0.
- mid: bắt đầu tại đầu mảng – con trỏ duyệt chính.
- high: bắt đầu tại cuối mảng (chỉ số n-1) – vùng chứa các 2.
Quy tắc xử lý khi mid <= high:
- Nếu
arr[mid] == 0: hoán đổiarr[mid]vớiarr[low], tăng cảlowvàmid. - Nếu
arr[mid] == 1: chỉ tăngmid(1 đã ở đúng vị trí giữa). - Nếu
arr[mid] == 2: hoán đổiarr[mid]vớiarr[high], giảmhigh(không tăngmidvì phần tử mới tạimidchưa được kiểm tra).
Triển khai Java
public class DNFSort {
public static void sort(int[] arr) {
int low = 0, mid = 0, high = arr.length - 1;
while (mid <= high) {
if (arr[mid] == 0) {
swap(arr, mid, low);
low++;
mid++;
} else if (arr[mid] == 1) {
mid++;
} else { // arr[mid] == 2
swap(arr, mid, high);
high--;
}
}
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] arr = {0, 0, 1, 0, 1, 0, 1, 2, 2};
sort(arr);
for (int v : arr) System.out.print(v + " ");
// Kết quả: 0 0 0 0 1 1 1 1 2
}
}
Phân tích độ phức tạp
- Thời gian: O(n) – duyệt mảng một lần.
- Không gian: O(1) – chỉ dùng vài biến phụ.
Đây là giải pháp tối ưu cho bài toán sắp xếp mảng 3 giá trị riêng biệt.