- Nếu a[M] < c thì gọi đề quy trên đoạn [M+1, R] B2:
7. Phơng án sắp xếp QuickSort
ý tởng của QuickSort cũng là chia mảng a cần sắp thành 2 phần nh phơng pháp trộn, tuy nhiên điểm chia đợc tính toán sao cho phù hợp.
để xác định đợc điểm chia, ta sử dụng hàm Partition(L, R). Hàm này sẽ sử dụng để trả về điểm chia làm cơ sở để chia mảng a. Nếu điểm chia là i thì:
i = Partition(L, R);
Khi có điểm chia rồi, ta sẽ chia a thành 2 nửa theo điểm chia và áp dụng việc sắp trên 2 nửa, trộn lại để thu đợc một mảng đã đợc sắp. Tuy nhiên để sắp trên 2 nửa của a, ta cũng áp dụng phơng pháp tơng tự. Nh vậy, giải thuật có thể nh sau:
{
int i= Partition(L, R); QuickSort(L, i-1); QuickSort(i+1, R); }
Vấn đề còn lại là hàm Partition xác định điểm chia nh thế nào. Ta có thể hình dung điều này nh sau:
B1: Lấy phần tử cuối cùng của mảng làm phần tử cầm canh (tức là a[R]).
B2: Cho i chạy từ trái sang cho tới khi gặp phần tử lớn hơn phần tử cầm canh. Cho j chạy từ bên phải về cho tới khi gặp phần tử nhở hơn phần tử cầm canh.
B3: Đảo chỗ hai phần tử a[i] cho a[j]. Cho i, j tiếp tục chạy nh trong B2. Tiếp tục đổi chỗ nh vậy cho tới khi i và j giao nhau (tức là i>=j).
B4: Đổi chỗ a[i] cho a[j] lần cuối. Khi đó, dễ thấy các phần tử bên trái của a[i] đều nhở hơn a[i] và các phần tử bên phải thì lớn hơn nó. Điểm i chính là điểm chia tìm đợc. return i;
Thuật toán này, thêm một chút cải tiến sẽ là thuật toán sắp xếp rất tốt (trong trờng hợp dữ liệu bất kỳ) với trung bình 2n.lg(n) phép so sánh.
Thật vậy, giải thuật Partition cần duyệt qua n phần tử để xác định điểm chia. Khi có điểm chia rồi ta cần sắp xếp các phần tử trên 2 nửa của mảng. (mỗi nửa tính trung bình có n/2 phần tử. Nh vậy tổng phí tổn là:
Cn = 2 Cn/2 + n.
Giải công thức truy hồi này cho ta đợc độ phức tạp: Cn = 2n.ln(n)
Biên soạn: Nguyễn Mạnh Cờng Trang 6 2
Chơng V: Kỹ thuật lập trình với con trỏ 1. Khai báo và sử dụng con trỏ