You are on page 1of 23

1

5.2. Sắp xếp nâng cao

5.2.1. Sắp xếp phân đoạn (Partition_Sort)


5.2.2. Sắp xếp vun đống (Heap_Sort)
5.2.3. Sắp xếp hoà nhập (Merge_Sort)
2
5.2.1. Sắp xếp phân đoạn
• Khái niệm: Sắp xếp phân đoạn (Partition_Sort) là 1 cải
tiến của phương pháp sắp xếp đổi chỗ (Exchange_Sort).
Người sáng lập ra phương pháp này - C.A.R. Hoare đặt
tên là sắp xếp NHANH (Quick_Sort).
• Nguyên tắc sắp xếp:
1. Lượt 1:
Chọn 1 khoá ngẫu nhiên của bảng khoá làm chốt (pivot). Mọi
khoá nhỏ hơn chốt phải xếp vào vị trí ở trước chốt, mọi khoá
lớn hơn chốt phải được xếp vào vị trí ở sau chốt bằng cách:
– Các khoá trong bảng được so sánh với chốt và sẽ đổi vị trí cho
nhau, hoặc cho chốt, nếu khoá lớn hơn chốt mà lại nằm trước
chốt hoặc khoá nhỏ hơn chốt mà lại nằm sau chốt.
3
Nguyên tắc sắp xếp
– Sau khi đổi chỗ bảng khoá được phân làm 2 đoạn: 1 đoạn gồm
các khoá nhỏ hơn chốt, 1 đoạn gồm các khoá lớn hơn chốt.
– Khoá chốt ở giữa 2 đoạn, đó chính là vị trí thực của nó trong
bảng khoá khi đã được sắp xếp.
– Kết thúc lượt 1.
2. Các lượt tiếp theo
– Thực hiện tương tự đối với các phân đoạn còn lại.
– Sắp xếp sẽ kết thúc khi phân đoạn cuối cùng được xử lý xong.
3. Kết quả:
– Bảng khoá đã được sắp xếp theo thứ tự tăng dần.
• Dùng phương pháp sắp xếp phân đoạn với bảng khoá:
42 23 74 11 65 58 94 36 99 87
4
Minh hoạ sắp xếp phân đoạn lượt 1
• Giả sử chọn chốt là khoá đầu tiên của bảng (42).
• Để phát hiện ra 2 khoá cần phải đổi chỗ cho nhau, ta
dùng 2 biến chỉ số i, j với giá trị ban đầu: i = 2, j = 10
• Các bước thực hiện:
B1: So sánh 42 và ki. Nếu ki < 42, tăng i lên 1. Quá trình lặp lại
đến khi ki > 42.
B2: Nếu ki > 42, so sánh kj với 42. Khi kj > 42, giảm j đi 1. Quá
trình lặp lại đến khi kj < 42.
B3: Nếu i < j, đổi chỗ kj với ki, quay lại B1, tiếp tục quá trình với j
cố định, còn i tăng. Nếu i  j, chuyển sang B4.
B4: Đổi chỗ 42 với kj. Kết thúc lượt 1. Khoá chốt (42) được xếp
đúng vị trí. Bảng khoá phân thành 2 đoạn.
Diễn biến của lượt 1 của Quick_Sort 5
Ghi chú
(chốt = 42, i=2, j=10, bảng khoá  2 đoạn)
So sánh 42 và ki, nếu ki<42 thì tăng i
42 23 74 11 65 58 94 36 99 87
lên 1. Lặp quá trình đến khi ki>42 (i=3)

Khi ki>42, so sánh 42 và kj, nếu kj>42


42 23 74 11 65 58 94 36 99 87
thì giảm j đi 1. Lặp đến khi kj<42 (j=8)

Do i<j (3<8) nên đổi chỗ:


42 23 36 11 65 58 94 74 99 87
ki = 74 và kj = 36

Quay lại B1 và lặp lại với j (j=8) cố


42 23 36 11 65 58 94 74 99 87
định và i tăng (i=3)... ki>42 (i=5)

Khi ki>42, so sánh 42 và kj, nếu kj>42


42 23 36 11 65 58 94 74 99 87
thì giảm j đi 1. Lặp đến khi kj<42 (j=4)

Do ij (54) nên đổi chỗ 42 và kj = 11.


11 23 36 42 65 58 94 74 99 87
Hết lượt 1: chốt = 42 vào đúng vị trí
– Mũi tên 1 chiều: Quá trình thực hiện so sánh khoá với chốt.
– Mũi tên 2 chiều: Thực hiện đổi chỗ 2 khoá.
– Sau lượt 1 bảng chia thành 2 đoạn: (11 23 36) 42 (65 58 94 74 99 87)
6
GT đệ quy Quick_Sort
• Mỗi lần bảng khoá được phân thành 2 đoạn thì ở lượt xử
lý tiếp theo chỉ 1 phân đoạn được sắp xếp, phân đoạn còn
lại sẽ được nhớ và xử lý sau.
• Việc nhớ và xử lý này sẽ được thực hiện bằng GT lặp
(dùng ngăn xếp - stack) hoặc bằng GT đệ quy.
• GT đệ quy được thực hiện như sau:
– Sử dụng 1 khoá giả k[n+1] mà k[i] < k[n+1] với 1  i  n.
– L và R là 2 chỉ số dưới và chỉ số trên (2 biên) của bảng được xử
lý. Lúc đầu L có giá trị bằng 1, còn R có giá trị bằng n.
– 2 chỉ số i, j dùng để lựa chọn khoá trong quá trình xử lý.
– Key là biến chứa giá trị của khoá chốt, ban đầu Key = k[1].
– B là biến logic, khởi đầu B = True, khi B = False thì bảng được
chia thành 2 bảng con.
7
GT đệ quy Quick_Sort
Procedure QUICKSORT(L, R : Byte);
Var i, j : Byte;
X, Key : Shortint;
B : Boolean;
Begin
B := true;
If L < R then
Begin
i := L; j := R + 1; Key := k[L]; {Chốt là khoá đầu tiên}
While B do
Begin
i := i + 1;
{Tăng i nếu k[i] < chốt} while k[i] < Key do i := i + 1;
j := j – 1;
{Giảm j nếu k[j] > chốt} while k[j] > Key do j := j - 1;
8
GT đệ quy Quick_Sort
If i < j then begin
{Đổi chỗ k[i] và k[j]} X := k[i]; k[i] := k[j]; k[j] := X;
end
Else B := false;
End;
{Đỗi chỗ chốt và k[j], k[L] là chốt theo cách chọn ban đầu}
X := k[L]; k[L] := k[j]; k[j] := X;
{Gọi đệ quy}
QUICKSORT(L, j - 1); {bảng con trước chốt}
QUICK_SORT(j + 1, R); {bảng con sau chốt}
End;
End;
Kết quả của sắp xếp theo QUICK_SORT 9
Ghi chú
Lượt 42 23 74 11 65 58 94 36 99 87
1 (11 23 36) 42 (65 58 94 74 99 87) Sắp xếp cả bảng, khoá chốt là 42
2 11 (23 36) 42 (65 58 94 74 99 87) Sắp xếp bảng con 1, chốt là 11
3 11 23 (36) 42 (65 58 94 74 99 87) Sắp xếp bảng con 11, chốt là 23
4 11 23 36 42 (65 58 94 74 99 87) Sắp xếp bảng con 12, chốt là 36
5 11 23 36 42 (58) 65 (94 74 99 87) Sắp xếp bảng con 2, chốt là 65
6 11 23 36 42 58 65 (94 74 99 87) Sắp xếp bảng con 21, chốt là 58
7 11 23 36 42 58 65 (87 74) 94 (99) Sắp xếp bảng con 22, chốt là 94
8 11 23 36 42 58 65 (74) 87 94 (99) Sắp xếp bảng con 221, chốt là 87
9 11 23 36 42 58 65 74 87 94 (99) Sắp xếp bảng con 2211, chốt là 74
10 11 23 36 42 58 65 74 87 94 99 Sắp xếp bảng con 222, chốt là 99
– Màu đỏ: Khoá được sắp xếp vào đúng vị trí sau mỗi lượt.
– Số của bảng con (ví dụ 221): Có số chữ số là số lần tách bảng con.
– 1: Bảng con đứng trước chốt.
– 2: Bảng con đứng sau chốt.
– Cách chọn khoá chốt: Là khoá đầu tiên trong bảng được xét
10
Các vấn đề ảnh hưởng tới QuickSort
1. Vấn đề chọn chốt.
– Chốt có thể chọn tuỳ ý trong bảng khoá, nhưng khi thể hiện GT
ta phải định ra 1 cách chọn chốt cụ thể.
– T/h xấu nhất: Nếu chốt rơi vào khoá nhỏ nhất (hoặc lớn nhất)
của phân đoạn cần xử lý thì sau mỗi lượt chỉ tách ra được 1
phân đoạn con có kích thước nhỏ hơn trước là 1 và phân đoạn
này sẽ được xử lý luôn. Như vậy, ta đã quay trở lại phương
pháp sắp xếp kiểu nổi bọt.
– T/h tốt nhất: Là chọn đúng trung vị (khoá có giá trị lớn hơn 1
nửa bảng khoá và nhỏ hơn 1 nửa bảng khoá còn lại) làm chốt.
Khi đó sau mỗi lượt, sẽ tách được 2 phân đoạn con có độ dài
gần như nhau, phân đoạn xử lý tiếp theo có kích thước chỉ bằng
“nửa” phân đoạn chứa nó. Tuy nhiên, không phải lúc nào cũng
chọn được đúng trung vị của bảng khoá.
11
Các vấn đề ảnh hưởng tới QuickSort
2. Vấn đề phối hợp với cách sắp xếp khác:
– Khi kích thước của các phân đoạn đã khá nhỏ, việc tiếp tục
phân đoạn nữa theo Quick_Sort sẽ không có lợi bằng cách sử
dụng 1 phương pháp sắp xếp đơn giản.
– Vì vậy, Quick_Sort thường không tiến hành triệt để mà dừng lại
ở lúc cần thiết để gọi tới 1 phương pháp sắp xếp đơn giản, giao
cho nó tiếp tục thực hiện sắp xếp với các phân đoạn nhỏ còn lại.
– Kunth (1974) có nêu:
“9 có thể coi là kích thước giới hạn của phân đoạn để sau đó
QUICK_SORT gọi tới phương pháp sắp xếp đơn giản.”
3. Vấn đề chọn phân đoạn nào để xử lý tiếp theo:
– Đây cũng là vấn đề cần được xem xét tới. Tuy nhiên ta sẽ
không đi sâu vào ở đây.
12
Đánh giá độ phức tạp GT Quick_Sort
• Ta công nhận các kết quả sau:
– T/h xấu nhất xảy ra khi bảng khoá vốn đã có thứ tự sắp xếp:
sau khi phân đoạn, 1 trong 2 bảng con là rỗng. T/h này
Quick_Sort không hơn các phương pháp đơn giản đã nêu.

– T/h tốt nhất xảy ra khi bảng luôn luôn được chia đôi.

– T/h trung bình đã được chứng minh:

• Kết luận: Khi n lớn, Quick_Sort tỏ ra có hiệu lực hơn


hẳn 3 phương pháp sắp xếp đơn giản.
13
5.2.2. Sắp xếp vun đống
• Nguyên tắc sắp xếp vun đống: Chia làm 2 giai đoạn.
1. G/đ tạo đống:
• Cây nhị phân biểu diễn bảng khoá biến đổi thành đống.
Ở đây: Đống là 1 cây nhị phân hoàn chỉnh mà mỗi nút được gán 1 giá trị
khoá sao cho khoá ở nút cha bao giờ cũng lớn hơn khoá ở nút con
của nó. Cây nhị phân được lưu trữ kế tiếp trong máy. 51
– Nếu j chỉ vị trí nút con, thì [j/2] chỉ
vị trí nút cha và theo định nghĩa ta có: 19
48
k[j/2] > kj với 1 ≤ [j/2] < j ≤ n
– Như vậy, khoá ở nút gốc của đống là khoá
lớn nhất (khoá trội) so với mọi khoá trên cây. 23 15 07
2. G/đ sắp xếp: Gồm nhiều lượt xử lý, mỗi lượt ứng với 2 phép:
– Đưa khoá trội về vị trí thực của nó bằng cách đổi chỗ với khoá hiện
đang ở vị trí đó.
– Vun lại thành đống đối với cây gồm các khoá còn lại (sau khi đã loại
khoá trội ra ngoài).
3. Kết quả: Bảng khoá đã được sắp xếp theo thứ tự tăng dần.
14
• Dùng phương pháp sắp xếp vun đống với bảng khoá:
42 23 74 11 65 58 94 36 99 87
• Bảng khoá được biểu diễn bằng cây nhị phân như hình a.
1. G/đ tạo đống:
– Cây nhị phân biểu diễn bảng khoá được biến đổi trở thành
đống như hình b.
– Đổi chỗ các khoá bằng cách xét từng nút trên cây nhị phân
theo nguyên tắc: khoá ở nút cha có giá trị lớn hơn ở nút con.
1 42 1 99

2 23 3 74 2 87 3 94

4 5 6 7 4 5 6 7
11 65 58 94 36 65 58 74

8 9 10 8 9 10
36 99 87 23 11 42
(Hình a) (Hình b)
42 15
– Quá trình tạo đống diễn ra chi tiết như sau: 1

• Nút 5: Đổi chỗ 87 và 65


• Nút 4: Đổi chỗ 99 và 11 2 23 3 94
• Nút 3: Đổi chỗ 94 và 74
• Nút 2: Đổi chỗ 99 và 23
4 5 6 7
sau đó đổi chỗ 36 và 23 (nút 4) 99 87 58 74

1 42
8 9 10
36 11 65
2 99 3 94 99
1

4 5 6 7 87 94
36 87 58 74 2 3

8 9 10 4 5 6 7
23 11 65 36 65 58 74

• Nút 1: Đổi chỗ 99 và 42


sau đó đổi chỗ 87 và 42 (nút 2) 8
23 9
11 42 10
sau đó đổi chỗ 65 và 42 (nút 5)
(Đống ban đầu)
16
2. G/đ sắp xếp: Gồm nhiều lượt, lượt sắp xếp 1 như sau:
B1: Khoá trội 99 được đưa vào vị trí cuối cùng bằng cách đổi chỗ
cho khoá 42, nút ứng với vị trí này coi như loại ra khỏi cây.
B2: Làm phép vun thành 1 đống mới đối với cây mới (cây mới với
các nút còn lại không còn là đống).
– Các lượt tiếp theo được thực hiện tương tự cho tới khi mọi
khoá đã vào đúng chỗ sắp xếp của nó.
– Minh hoạ lượt 1 như ở sau:
42 1 94
1

87 94 2 87 3 74
2 3

4 5 6 7
4
36 5
65 58 6 7
74 36 65 58 42

8 9 10
8
23 9
11 99 10 23 11 99
(B1) (B2)
– Minh hoạ các bước của GT sắp xếp vun đống: 17
Dãy S được sắp xếp, số nút N sau mỗi lượt và đống được tạo mới :
Lượt 1: S=(99), N=9 Lượt 2: S=(94,99), N=8
1 94 1 87

2 87 3 74 2 65 3 74

4 5 6 7 4 5 6 7
36 65 58 42 36 11 58 42

8 9 8
23 11 23
Lượt 3: S=(87,94,99), N=7 Lượt 4: S=(74,87,94,99), N=6
1 74 1 65

2 65 3 58 2 42 3 58

4 5 6 7 4 5 6
36 11 23 42 36 11 23
Lượt 5: S=(65,74,87,94,99), N=5 Lượt 6: S = (58,65,74,87,94,99), N=4 18

1 58 1 42

2 42 3 23 2 36 3 23

4 5 4
36 11 11

Lượt 7: S=(42,65,74,87,94,99), N=3 Lượt 8: S = (36,42,58,65,74,87,94,99), N=2

36 1 23
1

11 23 2 11
2 3

Lượt 9: S=(11,23,36,42,65,74,87,94,99), N=1. Đã xong

1 23
19
Đánh giá độ phức tạp GT Heap_Sort
• 1 cây nhị phân hoàn chỉnh có n nút thì chiều cao của cây là [log2(n
+ 1)]. Khi tạo đống cũng như khi vun đống trong giai đoạn sắp
xếp, trường hợp xấu nhất thì số lượng phép so sánh cũng chỉ tỉ lệ
với chiều cao của cây. Suy ra:
– T/h xấu nhất:
– T/h trung bình: (việc đánh giá phức tạp hơn, ta chỉ ghi nhận 1
kết quả đã chứng minh):
• Nhận xét:
– QUICK_SORT: Phải dùng thêm không gian nhớ cho stack, để
bảo lưu thông tin về các giai đoạn sẽ được xử lý tiếp theo (vì
thực hiện đệ quy).
– HEAP_SORT thì ngoài 1 nút nhớ phụ, để thực hiện đổi chỗ, nó
không cần thêm gì nữa.
• Kết luận: Khi n lớn, HEAP_SORT tỏ ra có hiệu lực hơn hẳn 3
phương pháp sắp xếp đơn giản đã nêu.
20
5.2.3. Sắp xếp hoà nhập
• Khái niệm: Sắp xếp hoà nhập (Merge_Sort) là phương
pháp dựa trên 1 phép xử lý đơn giản hơn sắp xếp để thực
hiện sắp xếp.
• Nhược điểm: Chi phí về không gian khá lớn. Nó đòi hỏi
tới 2n phần tử nhớ, gấp đôi so với các phương pháp thông
thường. Vì vậy, người ta thường sử dụng phương pháp
này khi sắp xếp ngoài, đối với các tập tin.
• Do tính chất riêng của sắp xếp hoà nhập nên trong bài
học chỉ giới thiệu sơ lược về phương pháp này.
• Độ phức tạp của GT Merge_Sort:
21
Kết luận
• Các phương pháp sắp xếp đơn giản đã thể hiện 3 kỹ thuật cơ
sở của sắp xếp (dựa vào phép so sánh các giá trị khoá) cấp độ
lớn của thời gian thực hiện chung là O(n2), vì vậy chỉ nên sử
dụng chúng khi n nhỏ.
• Các GT cải tiến Quick_Sort, Heap_Sort đã đạt được hiệu quả
cao: O(nlog2n) thường được sử dụng khi n lớn.
– Nếu bảng cần sắp xếp vốn có khuynh hướng hầu như “đã được sắp
sẵn” thì QUICK_SORT không nên dùng.
– Nếu ban đầu bảng có khuynh hướng ít nhiều có thứ tự ngược lại với
thứ tự sắp xếp thì HEAP_SORT lại tỏ ra thuận lợi.
• Merge_Sort không kém về thời gian thực hiện nhưng về
không gian thì đòi hỏi của nó không thích hợp với sắp xếp
trong.
• Việc khẳng định 1 GT nào luôn luôn tốt hơn mọi GT khác là
điều không nên. Việc lựa chọn 1 phương pháp sắp xếp thích
hợp tuỳ thuộc vào từng yêu cầu, từng điều kiện cụ thể.
22
5.4 Câu hỏi ôn tập
• Lý thuyết
1. Trình bày bài toán sắp xếp và phát biểu bt dạng đơn giản nhất.
2. Trình bày nguyên tắc sắp xếp của 3 kiểu sắp xếp đơn giản. Độ
phức tạp của các GT tương ứng?
3. Trình bày nguyên tắc sắp xếp của 2 kiểu sắp xếp cải tiến:
Quick_Sort, Heap_Sort. Độ phức tạp của các GT tương ứng?
• Thực hành
– Cho bảng khoá cần sắp xếp:
50 8 34 6 98 17 83 25 66 42 21 59 62 71 85 76
4. Hãy minh hoạ các lượt và chi tiết lượt 1 của 3 phương pháp
sắp xếp đơn giản qua bảng khoá trên theo thứ tự tăng dần.
5. Hãy minh hoạ các lượt và chi tiết lượt 1 của 3 phương pháp
sắp xếp đơn giản qua bảng khoá trên theo thứ tự giảm dần.
23
Câu hỏi ôn tập
6. Hãy sửa lại 3 GT sắp xếp đơn giản để thực hiện sắp xếp theo
thứ tự giảm dần.
7. Hãy minh hoạ 3 phương pháp sắp xếp đơn giản qua bảng khoá
trên theo thứ tự giảm dần.
8. Hãy minh hoạ các lượt và chi tiết lượt 1 của phương pháp sắp
xếp kiểu phân đoạn (Quick_Sort) qua bảng khoá trên theo thứ
tự tăng dần và giảm dần.
9. Hãy minh hoạ các lượt và chi tiết lượt 1 của phương pháp sắp
xếp kiểu vun đống (Heap_Sort) qua bảng khoá trên theo thứ tự
tăng dần và giảm dần. Nếu thực hiện sắp xếp theo thứ tự giảm
dần thì đống được định nghĩa như thế nào?
-----------------------

You might also like