Bài giảng Cấu trúc dữ liệu và giải thuật – Bài 6: Sắp xếp nhanh - Quick Sorts trình bày thuật toán QuickSort, ví dụ về QuickSort, hoạt động của QuickSort, hiệu quả của QuickSort. Mời các bạn cùng tham khảo bài giảng để nắm chi tiết nội dung kiến thức.
Trang 1Lecturer: PhD Ngo Huu Phuc
Tel: 0438 326 077 Mob: 098 5696 580 Email: ngohuuphuc76@gmail.com
Bài 6 Sắp xếp nhanh - Quick Sorts
Trang 2Bài 6 Quick Sorts
Trang 36.1 Thu ật toán QuickSort (1/6)
Gi ải thuật Quick-sort là
phương pháp sắp xếp dựa
trên chi ến lược chia để trị.
Phép chia : ch ọn ngẫu nhiên
Trang 46.1 Thu ật toán QuickSort (2/6)
Các bước cơ bản của thuật toán:
Chia tập dữ liệu ban đầu thành 2 tập con:
sao cho, tất cả các phần tử bên trái nhỏ hơn tất
cả các phần tử bên phải
Sắp xếp 2 tập con một cách độc lập và nối chúng
lại với nhau:
như vậy, ta được dãy đã sắp xếp
Trang 56.1 Thu ật toán QuickSort (3/6)
Với mỗi tập con trên, mỗi tập chia thành 02 tập con nếu có thể
như vậy, ta có tối đa 04 tập con
tập các phần tử nhỏ nhất ở bên trái cùng, tập các phần tử lớn nhất ở bên phải cùng
Lặp lại quá trình trên cho đến khi tập chỉ có 1
phần tử
nối tất cả các tập với nhau ta được dãy đã sắp
Trang 66.1 Thu ật toán QuickSort (4/6)
Ta chia tập dữ liệu ban đầu như sau:
Trên tập S, lấy mỗi phần tử y được lấy ra khỏi
tập
Đưa phần tử y vào tập L, E hay G, tùy thuộc
vào phép so sánh với khóa x
Với mỗi phép lấy 1 phần tử và đưa chúng vào tập tương ứng, độ phức tạp của phép toán đó là
O(1).
Như vậy, phép chia dữ liệu của thuật toán
QuickSort có độ phức tạp O(n).
Trang 76.1 Thu ật toán QuickSort (5/6)
7 4 9 6 2 → 2 4 6 7 9
Trang 86.1 Thu ật toán QuickSort (6/6)
Vi ệc thực thi giải thuật
QuickSort được mô tả qua
cây nh ị phân:
M ỗi node biểu diễn một
l ần gọi đệ quy và lưu giữ:
Dãy chưa được sắp xếp và
khóa.
Dãy sau khi sắp xếp.
Gốc của cây là lần gọi đệ
quy đầu tiên
Các lá c ủa cây là lần gọi
ứng với dãy con có kích
thước 0 hoặc 1.
Trang 96.2 Ví d ụ về QuickSort (1/7)
Chọn khóa
Trang 106.2 Ví d ụ về QuickSort (2/7)
Phân chia dãy ban đầu bằng gọi đệ quy với khóa đã chọn.
Trang 116.2 Ví d ụ về QuickSort (3/7)
Gọi đệ quy cho dãy con, với khóa mới
Trang 126.2 Ví d ụ về QuickSort (4/7)
Tương tự, gọi đệ quy, sau đó nối kết quả.
Trang 136.2 Ví d ụ về QuickSort (5/7)
Tương tự cho phần bên phải.
Trang 146.2 Ví d ụ về QuickSort (6/7)
Gọi đệ quy cho dãy con, với khóa mới
Trang 156.2 Ví d ụ về QuickSort (7/7)
Nối kết quả cho gốc của cây.
Trang 166.3 Ho ạt động của QuickSort (1/6)
Có th ể mô tả như sau:
V ới tập ban đầu, chọn 1 phần tử làm khóa.
Đổi chỗ phần tử đầu tiên với khóa.
S ử dụng 2 chỉ số i và j để duyệt phần còn lại trên dãy.
Ch ỉ số i tăng đến khi tại vị trí i đó, phần tử này có giá trị lớn hơn khóa Ch ỉ số j giảm đến khi giá trị tại vị trí j nhỏ hơn khóa.
So sánh gi ữa i và j, nếu i<j, đổi chỗ 2 phần tử này cho nhau
N ếu không, đổi chỗ khóa (phần tử đầu tiên) với phần tử j.
Khi đó, có thể chia mảng đã cho thành 2 mảng con, mảng thứ
nh ất từ vị trí 1 đến vị trí j-1, mảng thứ 2 từ vị trí j+1 đến n Sau
đó có thể lặp lại quá trình trên cho các mảng con.
Trang 176.3 Ho ạt động của QuickSort (2/6)
Ch ọn khóa:
Ta có thể chọn b ất kỳ phần tử nào trong mảng làm khóa
N ếu chọn phần tử đầu tiên của mảng làm khóa, lựa chọn này là tồi
n ếu mảng đã sắp xếp Khi đó, một mảng con có 0 phần tử Thông thường, chọn khóa gần với giữa của mảng với hi vọng lựa chọn này
s ẽ cho 2 mảng con có số phần tử gần bằng nhau.
Trang 18 QSort(S, a, b) s ẽ được gọi đệ quy cho các
m ảng con nhỏ hơn, với chỉ số thay đổi.
Trang 206.3 Ho ạt động của QuickSort (5/6)
#include "stdio.h"
#include "conio.h"
#define MAX 100
void swap( int *x, int *y);
int getkeyposition( int i, int j);
void qsort( int list[], int m, int n);
void inputdata( int list[], int n);
void printlist( int list[], int n);
printf("\n");
Trang 21while ((i <= n) && (list[i] <= key)) i++;
while ((j >= m) && (list[j] > key)) j ;
if ( i < j) swap(&list[i],&list[j]);
} swap(&list[m],&list[j]);
qsort(list,m,j-1);
qsort(list,j+1,n);
Trang 226.4 Hi ệu quả của Quicksort (1/6)
kích thước gần bằng n/4, thực hiện điều này đến khi kích
thước mỗi mảng bằng 1
Trang 236.4 Hi ệu quả của Quicksort (2/6)
Trong trường hợp tốt nhất (tiếp):
G ọi T(n) là th ời gian cần thiết để sắp n phần tử
khóa về đúng vị trí và thời gian để sắp 2 tập con có kích
thước gần bằng n/2 Do đó:
T(n) = c*n + 2*T(n/2)
Trang 246.4 Hi ệu quả của Quicksort (3/6)
Trong trường hợp tốt nhất (tiếp):
M ột cách tương tự, ta có:
T(n/2) = c*n/2 + 2*T(n/4)
T(n/4) = c*n/4 + 2*T(n/8), giả thiết T(1) = 1 Như vậy:
T(n) = c*n + 2(c*(n/2) + 2T(n/4))
T(n) = c*n + c*n + 4T(n/4)) = 2*c*n + 4T(n/4) = 2*c*n + 4(c*(n/4) + 2T(n/8))
T(n) = 2*c*n + c*n + 8T(n/8) = 3*c*n + 8T(n/8)
T(n) = (log n)*c*n + n T(n/n)= (log n)*c*n + n T(1) = n + n*(log n) *c
T(n) = O( n log(n))
Trang 256.4 Hi ệu quả của Quicksort (4/6)
Trong trường hợp tồi nhất:
Trang 266.4 Hi ệu quả của Quicksort (5/6)
Như vậy, với mỗi lần thực hiện Quick Sort, chỉ có
1 phần tử được sắp
Thực hiện việc này n lần
Mỗi lần, thời gian thực hiện cho quá trình chia
mảng con là O(n)
Như vậy, thời gian cho Quick sort trong trường
hợp này: O(n 2 ).
Trang 276.4 Hi ệu quả của Quicksort (6/6)
Đối với trường hợp trung bình?
đã chứng minh được, độ phức tạp: O(nlogn)
Trong thực tế, quicksort thường cho thấy sự hiệu
quả trong sắp xếp
có thể hình dung qua xác suất
với các tập có ít hơn 30 phần tử, quicksort
chưa cho thấy sự hiệu quả