04/2010
Bài toán sắp xếp
• Cho tập N phần tử, mỗi phần
tử có một số thuộc tính
• Dựa vào 1 (hoặc vài) thuộc tính
của các phần tử ñể sắp xếp lại
chúng theo trật tự mới.
KỸ THUẬT LẬP TRÌNH C
Chương 7: Các thuật toán sắp xếp
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
04/2010
Bài toán sắp xếp
Các giải thuật sắp xếp
• Gồm 2 bài toán con:
•
•
•
•
•
•
•
•
•
– Dựa theo khoá sắp xếp định vị lại thứ tự các
phần tử
– Chuyển các phần tử cần sắp về vị trí mới.
• Hai thao tác cơ bản
– So sánh
– Gán
Kỹ thuật lập trình C - Thuật toán sắp xếp
3
2
Sắp xếp đổi chỗ trực tiếp - Interchange Sort
Sắp xếp chọn trực tiếp – Selection Sort
Sắp xếp chèn trực tiếp – Insertion Sort
Sắp xếp nổi bọt – Buble Sort
Sắp xếp nổi bọt cải tiến - Shaker Sort
Shell sort
Heap sort
Quick sort
Merge sort
Kỹ thuật lập trình C - Thuật toán sắp xếp
4
04/2010
04/2010
Đổi chỗ trực tiếp – Interchange Sort
Đổi chỗ trực tiếp – Interchange Sort
• Khái niệm nghịch thế:
• Tìm tất cả nghịch thế, triệt tiêu chúng bằng
cách hoán vị 2 phần tử tương ứng trong
nghịch thế
– Xét một mảng các số a0, a1, . an.
– Nếu có i<j và ai > aj, thì ta gọi đó là một nghịch
thế.
• Mảng chưa sắp xếp sẽ có nghịch thế
• Mảng đã có thứ tự sẽ không chứa nghịch thế
Kỹ thuật lập trình C - Thuật toán sắp xếp
5
Kỹ thuật lập trình C - Thuật toán sắp xếp
6
04/2010
Đổi chỗ trực tiếp – Interchange Sort
Đổi chỗ trực tiếp – Interchange Sort
• Cho dãy số a:
12
2 8
• Bước 1 : i = 1; // bắt đầu từ ñầu dãy
• Bước 2 : j = i+1; //tìm các phần tử a[j] < a[i], j>i
• Bước 3 :
Trong khi j < N thực hiện
Nếu a[j]
Doicho(a[i],a[j]);
j = j+1;
• Bước 4 : i = i+1;
Nếu i < n: Lặp lại Bước 2.
Ngược lại: Dừng.
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
7
5
1
6
Kỹ thuật lập trình C - Thuật toán sắp xếp
4
15
8
04/2010
Đổi chỗ trực tiếp – Interchange Sort
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
Đổi chỗ trực tiếp – Interchange Sort
9
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
Đổi chỗ trực tiếp – Interchange Sort
Kỹ thuật lập trình C - Thuật toán sắp xếp
10
04/2010
Đổi chỗ trực tiếp – Interchange Sort
11
Kỹ thuật lập trình C - Thuật toán sắp xếp
12
04/2010
Interchange Sort - Kết quả
Đổi chỗ trực tiếp – Interchange Sort
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
13
12
2
8
5
1
6
4
15
2
12
8
5
1
6
4
15
1
12
8
5
2
6
4
15
1
8
12
5
2
6
4
15
1
5
12
8
2
6
4
15
1
2
12
8
5
6
4
15
1
2
8
12
5
6
4
15
1
2
5
12
8
6
4
15
1
2
4
12
8
6
5
15
1
2
4
8
12
6
5
15
1
2
4
6
12
8
5
15
1
2
4
5
12
8
6
15
1
2
4
5
8
12
6
15
1
2
4
5
6
12
8
15
4 Kỹ thuật lập 5trình C - Thuật6 toán sắp xếp8
12
15
14
1
2
04/2010
04/2010
Đổi chỗ trực tiếp – Interchange Sort
Các giải thuật sắp xếp
void InterchangeSort(int a[], int N )
{
int i, j;
for (i = 0 ; i
for (j =i+1; j < N ; j++)
if(a[j ]< a[i])// n u có s sai v trí thì ñ i ch
Doicho(a[i],a[j]);
}
•
•
•
•
•
•
•
•
•
Kỹ thuật lập trình C - Thuật toán sắp xếp
15
Sắp xếp đổi chỗ trực tiếp - Interchange Sort
Sắp xếp chọn trực tiếp – Selection Sort
Sắp xếp chèn trực tiếp – Insertion Sort
Sắp xếp nổi bọt – Buble Sort
Sắp xếp nổi bọt cải tiến - Shaker Sort
Shell sort
Heap sort
Quick sort
Merge sort
Kỹ thuật lập trình C - Thuật toán sắp xếp
16
04/2010
04/2010
Chọn trực tiếp – Selection Sort
Chọn trực tiếp – Selection Sort
• Chọn phần tử nhỏ nhất trong N phần tử ban ñầu
• Đưa phần tử này về vị trí ñúng là ñầu dãy hiện hành
• Xem dãy hiện hành chỉ còn N-1 phần tử của dãy
ban đầu
• Bước 1: i = 1;
• Bước 2: Tìm phần tử a[min] nhỏ nhất trong dãy hiện
hành từ a[i] ñến a[N]
• Bước 3 : Nếu min ≠ i thì ðổi chỗ a[min] và a[i]
– Bắt đầu từ vị trí thứ 2;
– Lặp lại quá trình trên cho dãy hiện hành... ñến khi dãy
hiện hành chỉ còn 1 phần tử
• Bước 4 : Nếu i < N-1 thì
i = i+1; Lặp lại Bước 2
Ngược lại: Dừng.
Kỹ thuật lập trình C - Thuật toán sắp xếp
17
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
Chọn trực tiếp – Selection Sort
• Cho dãy số a:
12 2
8
5
1
6
4
Kỹ thuật lập trình C - Thuật toán sắp xếp
18
04/2010
Chọn trực tiếp – Selection Sort
15
19
Kỹ thuật lập trình C - Thuật toán sắp xếp
20
04/2010
Chọn trực tiếp – Selection Sort
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
Chọn trực tiếp – Selection Sort
21
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
Selection sort
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
Các giải thuật sắp xếp
•
•
•
•
•
•
•
•
•
void SelectionSort(int a[],int N )
{
int min; // chỉ số phần tử nhỏ nhất trong dãy hiện hành
for (int i=0; i
{
min = i;
for(int j = i+1; j < N ; j++)
if (a[j] < a[min])
min = j; // ghi nhận vò trí phần tử nhỏ nhất
if (min != i)
Swap(a[min], a[i]);
}
}
22
23
Sắp xếp đổi chỗ trực tiếp - Interchange Sort
Sắp xếp chọn trực tiếp – Selection Sort
Sắp xếp chèn trực tiếp – Insertion Sort
Sắp xếp nổi bọt – Buble Sort
Sắp xếp nổi bọt cải tiến - Shaker Sort
Shell sort
Heap sort
Quick sort
Merge sort
Kỹ thuật lập trình C - Thuật tốn sắp xếp
24
04/2010
04/2010
Chèn trực tiếp – Insertion Sort
Chèn trực tiếp – Insertion Sort
• Giả sử có một dãy a1 , a2 ,... ,an trong ñó i phần tử
• Bước 1: i = 2;
// gi s có ño n a[1] ñã ñ c s p
• Bước 2: x = a[i]; Tìm vị trí pos thích hợp trong đoạn a[1]
đầu tiên a1 , a2 ,... ,ai-1 ñã có thứ tự.
đến a[i-1] ñể chèn a[i] vào
• Tìm cách chèn phần tử ai vào vị trí thích hợp của
đoạn đã được sắp để có dãy mới a1 , a2 ,... ,ai trở nên
có thứ tự. Vị trí này chính là vị trí giữa hai phần tử ak1 và ak thỏa ak-1 < ai < ak (1≤k≤i).
• Bước 3: Dời chỗ các phần tử từ a[pos] ñến
a[i-1] sang phải 1 vị trí ñể dành chổ cho a[i]
• Bước 4: a[pos] = x;
// có ño n a[1]..a[i] ñã ñ c s p
• Bước 5: i = i+1;
Nếu i < n : Lặp lại Bước 2.
Ngược lại : Dừng.
Kỹ thuật lập trình C - Thuật toán sắp xếp
25
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
Chèn trực tiếp – Insertion Sort
• Cho dãy số :
12 2
8
5
1
6
4
Kỹ thuật lập trình C - Thuật toán sắp xếp
26
04/2010
Chèn trực tiếp – Insertion Sort
15
27
Kỹ thuật lập trình C - Thuật toán sắp xếp
28
04/2010
04/2010
Insertion Sort – Cài đặt
Chèn trực tiếp – Insertion Sort
void InsertionSort(int a[], int N )
{
int pos, i;
int x;//lưu trữ a[i] tránh bò ghi đè khi dời chỗ các phần tử.
for(i=1 ; i
{
x = a[i];
for(pos=i;(pos>0)&&(a[pos-1]>x);pos--)
a[pos] = a[pos-1];
a[pos] = x;// chèn x vào dãy
}
}
Kỹ thuật lập trình C - Thuật tốn sắp xếp
29
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
Insertion Sort - Kết quả
12
04/2010
Các giải thuật sắp xếp
2
8
5
1
6
4
15
12
2
8
5
1
6
4
15
2
12
8
5
1
6
4
15
2
8
12
5
1
6
4
15
2
5
8
12
1
6
4
15
1
2
5
8
12
6
4
15
1
2
5
6
8
12
4
15
1
2
4
5
6
8
12
15
30
Kỹ thuật lập trình C - Thuật tốn sắp xếp
31
•
•
•
•
•
•
•
•
•
Sắp xếp đổi chỗ trực tiếp - Interchange Sort
Sắp xếp chọn trực tiếp – Selection Sort
Sắp xếp chèn trực tiếp – Insertion Sort
Sắp xếp nổi bọt – Buble Sort
Sắp xếp nổi bọt cải tiến - Shaker Sort
Shell sort
Heap sort
Quick sort
Merge sort
Kỹ thuật lập trình C - Thuật tốn sắp xếp
32
04/2010
04/2010
Nổi bọt – Bubble Sort
Nổi bọt – Bubble Sort
• Ý tưởng chính của giải thuật là xuất phát từ cuối
• Bước 1 : i = 1;
// l n x lý ñ u tiên
• Bước 2 : j = N;
//Duy t t cu i dãy ng c v v trí i
Trong khi (j > i) thực hiện:
Nếu a[j]
Doicho(a[j],a[j-1]);//xét c p ph n t k c n
j = j-1;
• Bước 3 : i = i+1; // lần xử lý kế tiếp
Nếu i > N - 1: Hết dãy. Dừng
Ngược lại
: Lặp lại Bước 2.
dãy, ñổi chỗ các cặp phần tử kế cận để ñưa phần tử
nhỏ hơn trong cặp phần tử ñó về vị trí ñúng đầu dãy
hiện hành, sau đó sẽ không xét đến nó ở bước tiếp
theo, do vậy ở lần xử lý thứ i sẽ có vị trí ñầu dãy là i .
Kỹ thuật lập trình C - Thuật toán sắp xếp
33
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
Nổi bọt – Bubble Sort
• Cho dãy số a:
2
12 8
5
1
34
04/2010
Nổi bọt – Bubble Sort
6
Kỹ thuật lập trình C - Thuật toán sắp xếp
4
15
35
Kỹ thuật lập trình C - Thuật toán sắp xếp
36
04/2010
Nổi bọt – Bubble Sort
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
Nổi bọt – Bubble Sort
37
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
38
04/2010
Bubble sort - Caøi ñaët
Nổi bọt – Bubble Sort
void BubbleSort(int a[], int N)
{
int i, j;
for (i = 0 ; i < N-1 ; i++)
for (j = N-1; j>i ; j --)
if(a[j]< a[j-1])
Swap(a[j], a[j-1]);
}
Kỹ thuật lập trình C - Thuật toán sắp xếp
39
Kỹ thuật lập trình C - Thuật toán sắp xếp
40
04/2010
Bubble Sort - Kết quả
Các giải thuật sắp xếp
12
2
8
5
1
6
4
15
12
2
8
5
1
4
6
15
12
2
8
1
5
4
6
15
12
2
1
8
5
4
6
15
12
1
2
8
5
4
6
15
1
12
2
8
5
4
6
15
1
12
2
8
4
5
6
15
1
12
2
4
8
5
6
15
1
2
12
4
8
5
6
15
1
2
12
4
5
8
6
15
1
2
4
12
5
8
6
15
1
2
4
12
5
6
8
15
1
2
4
5
12
6
8
15
1
2
4
5
6
12
4 Kỹ thuật lập5trình C - Thuật
6 toán sắp xếp
8
8
15
12
15
41
1
2
04/2010
•
•
•
•
•
•
•
•
•
Sắp xếp đổi chỗ trực tiếp - Interchange Sort
Sắp xếp chọn trực tiếp – Selection Sort
Sắp xếp chèn trực tiếp – Insertion Sort
Sắp xếp nổi bọt – Buble Sort
Sắp xếp nổi bọt cải tiến - Shaker Sort
Shell sort
Heap sort
Quick sort
Merge sort
Kỹ thuật lập trình C - Thuật toán sắp xếp
04/2010
Shaker Sort
• Dựa trên nguyên tắc đổi chỗ trực tiếp
42
04/2010
Shaker Sort
void ShakeSort(int data[], int n){
int i, j, left, right, k;
left = 0; right = d.n-1; k = n-1;
Khắc
phục nhược điểm của Bubble Sort.
while (left < right) {
for (j = right; j > left; j--)
if (data[j]< data[j-1]){
Doicho(data[j], data[j-1]);
k =j;
}
left = k;
for (j = left; j < right; j++)
if (data[j]> data[j+1]) {
Doicho(data[j],data[j-1]);
k = j;
}
right = k;
}
• Trong mỗi lần sắp xếp, duyệt mảng theo 2 lượt
từ 2 phiá khác nhau :
– Lượt đi: đẩy phần tử nhỏ về ñầu mảng
– Lượt về: đẩy phần tử lớn về cuối mảng
• Ghi nhận lại những đoạn đã sắp xếp nhằm tiết
kiệm các phép so sánh thừa.
}
Kỹ thuật lập trình C - Thuật toán sắp xếp
43
Kỹ thuật lập trình C - Thuật toán sắp xếp
44
04/2010
Các giải thuật sắp xếp
•
•
•
•
•
•
•
•
•
• Đònh nghóa heap:
Sắp xếp đổi chỗ trực tiếp - Interchange Sort
Sắp xếp chọn trực tiếp – Selection Sort
Sắp xếp chèn trực tiếp – Insertion Sort
Sắp xếp nổi bọt – Buble Sort
Sắp xếp nổi bọt cải tiến - Shaker Sort
Shell sort
Heap sort
Quick sort
Merge sort
– Heap là một dãy các phần tử aleft, aleft+1,... , aright
thoả các quan hệ:
• ai ≥ a2i
• ai ≥ a2i+1
với ∀i ∈ [left, right]
– Khi đó (ai , a2i), (ai ,a2i+1) được gọi là các cặp
phần tử liên đới.
– Heap được đònh nghóa như trên được dùng trong
trường hợp sắp xếp tăng dần, khi sắp xếp giảm
dần phải đổi chiều các quan hệ.
Kỹ thuật lập trình C - Thuật tốn sắp xếp
Sắp xếp vun đống - Heap sort
04/2010
45
04/2010
Ví dụ dãy là heap:
1
2
3
4
5
6
7
8
15
12
8
5
1
4
6
2
Kỹ thuật lập trình C - Thuật tốn sắp xếp
46
Sắp xếp vun đống – Heap sort
a1
a2
a4
Các phần tử
của dãy được
biểu diễn theo
các mối quan
hệ liên đới
a3
a5
a6
04/2010
a7
a8
Kỹ thuật lập trình C - Thuật tốn sắp xếp
47
Kỹ thuật lập trình C - Thuật tốn sắp xếp
48
Sắp xếp vun đống - Heap sort
04/2010
04/2010
Sắp xếp vun đống - Heap sort
• Một số tính chất của Heap:
• Sắp xếp dãy tăng dần qua 2 giai đoạn:
– Tính chất 1: Nếu aleft, aleft+1, …, aright là một heap
thì khi cắt bỏ một số phần tử ở hai đầu của heap,
dãy con còn lại vẫn là một heap.
– Tính chất 2: Nếu a1, a2, …, an là một heap thì phần
tử a1 (đầu heap) luôn là phần tử lớn nhất trong
heap.
– Tính chất 3: Mọi dãy con aleft, aleft+1, ..., aright thỏa:
2left > right đều là heap.
Kỹ thuật lập trình C - Thuật tốn sắp xếp
Heap sort – Giai đoạn 1
– Giai đoạn 1: hiệu chỉnh dãy ban đầu thành heap
– Giai đoạn 2: sắp xếp heap có được sau giai đoạn
1 thành dãy tăng dần
49
04/2010
Tạo heap
1
2
3
4
5
6
7
8
12
2
12
2
8
5
1
6
4
15
8
15
1
6
4
5
12
12
15
8
2
1
6
4
5
15
8
5
1
6
4
2
15
12
8
5
1
6
4
2
n = 8, n/2 = 4
Xuất phát từ a[4], so sánh với a[8]
đổi chổ
a[3] so sánh với a[6], a[7]
a[2] so sánh với a[4], a[5]
a[2]↔
↔a[4]
lan truyền so sánh a[4] với a[8]
• …
•
•
•
•
//Lưu ý: đoạn aleft+1, …, aN đã là heap
• Bước 21: Hiệu chỉnh đoạn aleft, …, aN thành heap
• Bước 22: left = left - 1;
//Hết lặp
Kỹ thuật lập trình C - Thuật tốn sắp xếp
50
04/2010
//input: dãy (a, N)
//output: dãy (a, N) là một heap
• Bước 1: left = N/2; //Thêm các phần tử aleft, ..,
a1 vào heap
• Bước 2: Trong khi left > 0
Kỹ thuật lập trình C - Thuật tốn sắp xếp
51
Kỹ thuật lập trình C - Thuật tốn sắp xếp
52
04/2010
04/2010
Heap sort – Giai đoạn 2
Heap sort – Giai đoạn 2
• Vấn đề: Sắp xếp heap a1, …, aN thành dãy tăng dần
//Đặt: right = N Ł dãy a1, …, aright là heap.
• Ý tưởng:
//input: dãy (a, N) là heap
//output: dãy (a, N) sắp tăng dần
• Bước 1: right = N; //Bắt đầu thực hiện từ cuối dãy
• Bước 2: Trong khi right > 1
– Theo tính chất 2: a1 sẽ là phần tử lớn nhất, vì vậy vò trí đúng
của a1 phải là right - cuối dãy.
//Đưa phần tử lớn nhất (a1)về vò trí right
• Bước 2.1: Hoánvò (a1 , aright);
//Loại bỏ phần tử lớn nhất ra khỏi heap
• Bước 2.2: right := right -1;
• Bước 2.3: Hiệu chỉnh đoạn a1, a2, …, aright thành heap
Ł Đổi chổ (a1, aright) Ł được thêm một phần tử ở đúng vò trí
q Theo tính chất 3: dãy con a2, …, aright-1 vẫn là heap
Ł Giảm right, thêm a1 vào dãy và hiệu chỉnh lại
Ł dãy a1, …, aright là heap.
//Hết lặp
Kỹ thuật lập trình C - Thuật tốn sắp xếp
53
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
Hiệu chỉnh heap
04/2010
Các giải thuật sắp xếp
1
2
3
4
5
6
7
8
15
12
8
5
1
6
4
2
2
12
8
5
1
6
4
15
12
2
8
5
1
6
4
15
12
5
8
2
1
6
4
15
4
5
8
2
1
6
12
15
• Đỗi chổ a[1] ↔ a[8]
có 1 phần tử đã đúng vị trí
• Tiến hành tương tự cho dãy n-1 phần tử
Lưu ý: Chỉ cần xét phần tử a[1]
54
Kỹ thuật lập trình C - Thuật tốn sắp xếp
55
•
•
•
•
•
•
•
•
•
Sắp xếp đổi chỗ trực tiếp - Interchange Sort
Sắp xếp chọn trực tiếp – Selection Sort
Sắp xếp chèn trực tiếp – Insertion Sort
Sắp xếp nổi bọt – Buble Sort
Sắp xếp nổi bọt cải tiến - Shaker Sort
Shell sort
Heap sort
Quick sort
Merge sort
Kỹ thuật lập trình C - Thuật tốn sắp xếp
56
04/2010
Quick sort – Ý tưởng
Quick sort – Ý tưởng
• Giải thuật QuickSort sắp xếp dãy a1, a2 ..., aN dựa
trên việc phân hoạch dãy ban đầu thành 3 phần :
– Phần 1: Gồm các phần tử có giá trò không lớn hơn x
– Phần 2: Gồm các phần tử có giá trò bằng x
– Phần 3: Gồm các phần tử có giá trò không bé hơn x
với x là giá trò của một phần tử tùy ý trong dãy
ban đầu.
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
57
• Sau khi thực hiện phân hoạch, dãy ban đầu được
phân thành 3 đoạn:
– 1. ak < x , với k = 1 .. j
– 2. ak = x , với k = j+1 .. i-1
– 3. ak > x , với k = i..N
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
Quick sort – Ý tưởng
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
Quick sort – Ý tưởng
• Đoạn thứ 2 đã có thứ tự.
• Nếu các đoạn 1 và 3 có nhiều hơn 1 phần tử
thì dãy ban đầu chỉ có thứ tự khi các đoạn 1,
3 được sắp.
• Để sắp xếp các đoạn 1 và 3, ta lần lượt tiến
hành việc phân hoạch từng dãy con theo
cùng phương pháp phân hoạch dãy ban đầu
vừa trình bày …
• Đoạn thứ 2 đã có thứ tự.
• Nếu các đoạn 1 và 3 chỉ có 1 phần tử: đã có
thứ tự
khi đó dãy con ban đầu đã được sắp.
58
59
Kỹ thuật lập trình C - Thuật tốn sắp xếp
60
04/2010
04/2010
Quick sort – Giải thuật
Quick sort – Phân hoạch dãy
• Bước 1: Nếu left ≥ right //dãy có ít hơn 2 phần tử
//input: dãy con aleft, …, aright
//output: dãy con chia thành 3 đoạn: đoạn 1 ≤ đoạn 2 ≤ đoạn 3
• Bước 1: Chọn tùy ý một phần tử a[p] trong dãy con là giá trò mốc:
Kết thúc;
//dãy đã được sắp xếp
x = a[p];
• Bước 2: Phân hoạch dãy aleft … aright thành các
đoạn: aleft.. aj, aj+1.. ai-1, ai.. Aright
• Bước 2: Duyệt từ 2 đầu dãy để phát hiện và hiệu chỉnh cặp phần tử
a[i], a[j] vi phạm điều kiện
–
–
–
–
Đoạn 1 ≤ x
Đoạn 2: aj+1.. ai-1 = x
Đoạn 3: ai.. aright ≥ x
• Hoán vò (a[i],a[j]);
• Bước 3: Sắp xếp đoạn 1: aleft.. aj
• Bước 4: Sắp xếp đoạn 3: ai.. aright
Bước 21: i = left; j = right;
Bước 22: Trong khi (a[i]
Bước 23: Trong khi (a[j]>x) j--;
Bước 24: Nếu i<= j // a[i] ≥ x ≥ a[j] mà a[j] đứng sau a[i]
– Bước 25: Nếu i < j:
//Hết duyệt
Kỹ thuật lập trình C - Thuật tốn sắp xếp
61
i++; j--;
Lặp lại Bước 22.//chưa xét hết mảng
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
Quick sort – Ví dụ
• Cho dãy số a:
12
2 8
5
62
04/2010
Quick sort – Ví dụ
1
6
4
15
Phân hoạch đoạn l =1, r = 8: x = A[4] = 5
Kỹ thuật lập trình C - Thuật tốn sắp xếp
63
Kỹ thuật lập trình C - Thuật tốn sắp xếp
64
04/2010
Quick sort – Ví dụ
04/2010
Quick sort – Ví dụ
• Phân hoạch đoạn l =1, r = 3:
• Phân hoạch đoạn l = 5, r = 8:
x = A[2] = 2
Kỹ thuật lập trình C - Thuật tốn sắp xếp
65
x = A[6] = 6
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
66
04/2010
Quick sort – Cài đặt
• Phân hoạch đoạn l = 7, r = 8:
Kỹ thuật lập trình C - Thuật tốn sắp xếp
x = A[7] = 6
67
void QuickSort(int a[], int left, int right)
{
int i, j, x;
if (left ≥ right)
return;
x = a[(left+right)/2]; // chọn phần tử giữa làm giá trò mốc
i = left; j = right;
while(i < j) {
while(a[i] < x) i++;
while(a[j] > x) j--;
if(i <= j) {
Swap(a[i], a[j]);
i++ ; j--;
}
}
if(left < j)
QuickSort(a, left, j);
QuickSort(a, i, right);
if(i < right)
}
Kỹ thuật lập trình C - Thuật tốn sắp xếp
68
04/2010
Merge sort – Ý tưởng
Các giải thuật sắp xếp
•
•
•
•
•
•
•
•
•
• Giải thuật Merge sort sắp xếp dãy a1, a2, ...,
an dựa trên nhận xét sau:
Sắp xếp đổi chỗ trực tiếp - Interchange Sort
Sắp xếp chọn trực tiếp – Selection Sort
Sắp xếp chèn trực tiếp – Insertion Sort
Sắp xếp nổi bọt – Buble Sort
Sắp xếp nổi bọt cải tiến - Shaker Sort
Shell sort
Heap sort
Quick sort
Merge sort
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
– Mỗi dãy a1, a2, ..., an bất kỳ là một tập hợp các
dãy con liên tiếp mà mỗi dãy con đều đã có thứ
tự.
• Ví dụ: dãy 12, 2, 8, 5, 1, 6, 4, 15 có thể coi như
gồm 5 dãy con không giảm (12); (2, 8); (5); (1, 6);
(4, 15).
– Dãy đã có thứ tự coi như có 1 dãy con.
Ł Hướng tiếp cận: tìm cách làm giảm
số dãy con không giảm của dãy ban
đầu.
69
Kỹ thuật lập trình C - Thuật tốn sắp xếp
70
04/2010
Merge sort
04/2010
Merge sort – Ví dụ
• Bước 1 : k = 1; // dãy con có 1 phần tử là dãy không
giảm
k = 1;
• Bước 2 : Lặp trong khi (k < N) // dãy còn hơn 1 dãy con
– Bước 21: Phân phối đều luân phiên dãy a1, a2, …, an thành 2
dãy b, c theo từng nhóm k phần tử liên tiếp nhau.
1
2
3
4
5
6
7
8
12
2
8
5
1
6
4
15
//b = a1, …, ak, a2k+1, …, a3k, …
//c = ak+1, …, a2k, a3k+1, …, a4k, …
Phân phối đều luân phiên
– Bước 22: Trộn từng cặp dãy con gồm k phần tử của 2 dãy b,
c vào a.
– Bước 23: k = k*2;
Kỹ thuật lập trình C - Thuật tốn sắp xếp
71
Kỹ thuật lập trình C - Thuật tốn sắp xếp
72
04/2010
Merge sort – Ví dụ
Merge sort – Ví dụ
1
2
3
4
5
6
7
8
12
2
8
5
1
6
4
15
Kỹ thuật lập trình C - Thuật tốn sắp xếp
Trộn từng cặp đường chạy
k = 1;
Phân phối đều luân phiên
k = 1;
04/2010
73
1
2
3
4
12
8
1
4
2
5
6
15
5
6
7
Kỹ thuật lập trình C - Thuật tốn sắp xếp
74
04/2010
Merge sort – Ví dụ
1
2
3
4
12
8
1
4
2
5
6
15
04/2010
Merge sort – Ví dụ
Trộn từng cặp đường chạy
k = 1;
8
5
Kỹ thuật lập trình C - Thuật tốn sắp xếp
6
7
8
75
k = 2;
Phân phối đều luân phiên
1
2
3
4
5
6
7
8
2
12
5
8
1
6
4
15
Kỹ thuật lập trình C - Thuật tốn sắp xếp
76
04/2010
Merge sort – Ví dụ
Merge sort – Ví dụ
Trộn từng cặp đường chạy
k = 2;
1
2
3
4
2
12
1
5
8
4
5
6
7
8
Trộn từng cặp đường chạy
k = 2;
1
2
3
4
6
2
12
1
6
15
5
8
4
15
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
77
5
6
7
Kỹ thuật lập trình C - Thuật tốn sắp xếp
78
04/2010
Merge sort – Ví dụ
k = 4;
04/2010
Merge sort – Ví dụ
Phân phối đều luân phiên
1
2
3
4
5
6
7
8
2
5
8
12
1
4
6
15
8
Kỹ thuật lập trình C - Thuật tốn sắp xếp
79
Trộn từng cặp đường chạy
k = 4;
1
2
3
4
2
5
8
12
1
4
6
15
5
Kỹ thuật lập trình C - Thuật tốn sắp xếp
6
7
8
80
04/2010
04/2010
Merge sort – Ví dụ
Trộn từng cặp đường chạy
k = 4;
1
Merge sort – Ví dụ
2
3
4
5
6
7
k = 8;
8
1
2
3
4
5
6
7
8
1
2
4
5
6
8
12
15
2
5
8
12
STOP
1
4
6
15
Only one
subarray
Kỹ thuật lập trình C - Thuật tốn sắp xếp
81
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
04/2010
Merge Sort – Cài đặt
Merge sort – Ví dụ
•
Dữ liệu hỗ trợ: 2 mảng b, c:
int
•
1
1
2
2
3
4
4
5
82
5
6
6
8
7
12
8
15
b[MAX], c[MAX], nb, nc;
Các hàm cần cài đặt:
– MergeSort: Sắp xếp mảng (a, N) tăng dần
void MergeSort(int a[], int N);
– Distribute: Phân phối đều luân phiên các dãy con độ dài k từ mảng a vào
hai mảng b và c
void Distribute(int a[], int N,
int &nb, int &nc, int k);
– Merge: Trộn mảng b và mảng c vào mảng a
void Merge(int a[], int nb, int nc, int k);
– MergeSubarr: Trộn 1 cặp dãy con từ b và c vào a
void MergeSubarr(int a[], int nb, int nc,
int &pa, int &pb, int &pc, int k);
Kỹ thuật lập trình C - Thuật tốn sắp xếp
83
Kỹ thuật lập trình C - Thuật tốn sắp xếp
84
04/2010
Merge sort – Cài đặt
Merge sort – Cài đặt
//khai báo 2 mảng phụ
void Distribute(int
a[], int
N,
int &nb, int &nc, int k)
{
int i, pa, pb, pc;
pa = pb = pc = 0;
while (pa < N)
{
for (i=0; (pa
b[pb] = a[pa];
for (i=0; (pa
c[pc] = a[pa];
}
nb = pb; nc = pc;
}
int b[MAX], c[MAX], nb, nc;
void MergeSort(int a[], int N)
{
int k;
for (k = 1; k < N; k *= 2)
{
Distribute(a, N, nb, nc, k);
Merge(a, nb, nc, k);
}
}
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
85
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
Merge sort – Cài đặt
Kỹ thuật lập trình C - Thuật tốn sắp xếp
04/2010
Merge sort – Cài đặt
void MergeSubarr(int a[], int nb, int nc,
int &pa, int &pb, int &pc, int k)
{
int rb, rc;
rb = min(nb, pb+k); rc = min(nc, pb+k);
while ((pb < rb) && (pc < rc))
if (b[pb] < c[pc])
a[pa ++] = b[pb ++];
else a[pa ++] = c[pc ++];
while (pb < rb)
a[pa ++] = b[pb ++];
while (pc < rc)
a[pa ++] = c[pc ++];
}
void Merge(int a[], int nb, int nc, int k)
{
int pa, pb, pc;
pa = pb = pc = 0;
while ((pb < nb) && (pc < nc))
MergeSubarr(a, nb, nc, pa, pb, pc, k);
while (pb < nb)
a[pa ++] = b[pb ++];
while (pc < nc)
a[pa ++] = c[pc ++];
}
86
87
Kỹ thuật lập trình C - Thuật tốn sắp xếp
88
04/2010
Kỹ thuật lập trình C - Thuật toán sắp xếp
89