1 Sắp thứ tự
Dec 31, 2015
1
Sắp thứ tự
2
1. Phương pháp chèn (Insertion sort)Nội dung phương pháp:
• Xét dãy a1, …., ai-1 có thứ tự, tìm vị trí thích hợp của ai trong dãy trên để chèn vào sao cho ta được dãy a1, …., ai có thứ tự.
• Thực hiện với i = 2, ….., n ta được dãy a1, …., an có thứ tự
3
Ví dụ
1 2 3 4 5 6 7 8
7 1 6 9 3 5 4 8
1 7 6
1 6 7 9
1 6 7 9 3
1 3 6 7 9 5
1 3 5 6 7 9
X= 5
4
Giải thuật chèn• Thực hiện với i=2 , …, n:
1. x = ai
2. j = i-1
3. Khi (j>0) Λ (x<aj)
3. 1 aj+1=aj
3. 2 j = j-1
4. aj+1=x
5
Độ phức tạp
• Số phép gán:
• Số phép so sánh:
6
Cài đặtvoid insertionsort(elem a[], int n, int (*comp)(elem, elem)){
int i, j, sz=sizeof(elem);elem x;for (i=1; i<n; i++){
memcpy(&x, &a[i], sz);j = i-1;while (j>=0 && comp(x, a[j])<0){
memcpy(&a[j+1], &a[j], sz);j--;
}memcpy(&a[j+1], &x, sz);
}}
7
2. Phương pháp chọn (Selection sort)Nội dung phương pháp:
• Chọn phần tử nhỏ nhất trong dãy ai, …., an là ak
• Hoán đổi phần tử ai với ak.
Thực hiện với i = 1, ….., n-1 ta được dãy a1, …., an có thứ tự
8
Ví dụ
1 2 3 4 5 6 7 8
7 1 6 9 3 5 4 8
1 7 6 9 3 5 4 8
1 3 6 9 7 5 4 8
1 3 4 9 7 5 6 8
1 3 4 5 7 9 6 8
1 3 4 5 6 9 7 8
…
9
Giải thuật chọn• Với i=1 , …, n-1, thực hiện:
1. k=i
2. x = ak
3. Với j = i+1, …, n, thực hiện:
Nếu x>aj
– k=j
– x=ak
4. ak = ai
5. ai=x
10
Độ phức tạp
• Số phép gán:
• Số phép so sánh:
11
Cài đặtvoid selectionsort(elem a[], int n, int (*comp)(elem, elem)){ int i, j, k, sz=sizeof(elem);
elem x;for (i=0; i<n-1; i++){
k = i;memcpy(&x, &a[k], sz);for (j=i+1; j<n; j++)
if (comp(x, a[j])>0){
k = j;memcpy(&x, &a[k], sz);
}memcpy(&a[k], &a[i], sz);memcpy(&a[i], &x, sz);
}}
12
Cài đặtvoid selectionsort(elem a[], int n, int (*comp)(elem, elem)){ int i, j, k, sz=sizeof(elem);
elem x;for (i=0; i<n-1; i++){
k = i;for (j=i+1; j<n; j++)
if (comp(a[k], a[j])>0)k = j;
memcpy(&x, &a[k], sz);memcpy(&a[k], &a[i], sz);memcpy(&a[i], &x, sz);
}}
13
3. Phương pháp đổi chổNội dung phương pháp:
Duyệt qua dãy, nếu 2 phần tử kề nhau không thứ tự thì hoán đổi
Thực hiện cho đến khi dãy có thứ tự
Thuật giải nổi bọt (Bubble sort)
Phép duyệt: duyệt từ cuối về đầu dãy -> phần tử nhỏ nhất về đầu dãy: nổi bọt
14
Thuật giải (C)
for (i=1; i<n; i++)
for (j=n-1; j>=i; j--)
if (a[j]<a[j-1])
swap(a[j], a[j-1]);
// Phải viết hàm swap(x, y) hoán vị x và y
15
Sap thu tu - phuong phap noi botvoid bubblesort(elem a[], int n, int (*comp)(elem, elem)){
int i, j, sz=sizeof(elem);elem x;for (i=1; i<n; i++)
for (j=n-1; j>=i; j--)if (comp(a[j], a[j-1])<0){
memcpy(&x, &a[j], sz);memcpy(&a[j], &a[j-1], sz);memcpy(&a[j-1], &x, sz);
}}
16
Thuật giải BS có sử dụng cờ(C)i=1; do {
OK = 1;for (j=n-1; j>=i; j--)
if (a[j]<a[j-1]){
swap(a[j], a[j-1]);OK = 0;
}i++;
} while (!OK);
17
Thuật giải Sàng (Shaker sort)Nội dung phương pháp:
Thực hiện lặp 2 quá trình liên tiếp:
Duyệt từ phải qua trái: Nổi bọt
Duyệt từ trái qua phải: Lắng đọng
Mỗi quá trình ghi nhận vị trí hóa đổi sau cùng làm điểm xuất phát cho quá trình tiếp theo
Thực hiện cho đến khi phải vượt trái
18
Thuật giải Shaker sort(C)l = 1;
r = k = n-1;
do {
for (j=r; j>=l; j--)
if (a[j]<a[j-1])
{
swap(a[j], a[j-1]);
k = j;
}
l = k+1;
for (j=l; j>=r; j++)
if (a[j]<a[j-1])
{
swap(a[j], a[j-1]);
k = j;
}
r = k-1;
} while (l<=r);
19
II. Các thuật giải kải tiến
20
1. Giải thuật “vun đống” (Heap sort)
Cải tiến từ phương pháp chọn
Định nghĩa:
• Heap: Là cấu trúc cây nhị phân đầy đủ theo nghĩa: các nút được bố trí tuần tự từ mức thấp đến mức cao, từ trái qua phải
Ví dụ:
21
Giải thuật “vun đống” (Heap sort)• Heap max (min): Là cấu trúc heap thỏa điều
kiện : mọi nút đều có khóa lớn (nhỏ) hơn 2 con
Ví dụ: 9
68
7 0 35
214
22
Tổ chức heap từ dãy• Với dãy a1, a2, ….. an ta tổ chức thành cấu trúc
heap như sau:
ai có 2 con là a2i và a2i+1
Vẽ lại
a1 a2 a3 a4 a5 a6 a7
a1
a2a3
a6a5a4 a7
a10a9a8
23
Khởi tạo heap max ban đầu• Ta có ai với i=n/2+1, … n là các nút lá trên cây
nên hiển nhiên thỏa mãn tính chất heap max
• Để khởi tạo heap max ban đầu ta tìm cách biến đổi ai (với i=n/2, …, 1) thành heap max khi ai+1, …, an thỏa heap max
a1
a2a3
a6a5a4 a7
a10a9a8
24
Sắp thứ tự
• Khi i=1 ta có dãy thỏa mãn tính chất heap max, nghĩa là a1 là phần tử lớn nhất
• Để sắp thứ tự, phần tử lớn nhất phải nằm cuối nên ta hoán đổi phần tử a1 với an
• Biến đổi a1 thành heap max khi a2, …, an-1 thỏa heap max
• Tiếp tục hoán đổi và biến đổi cho đến khi dãy có thứ tự
25
Giải thuật biến đổi heap max (q, r)
4
9 7
186 0
325
9
8 7
146 0
325
4
26
9
8 7
146 0
325
3
8 7
146 0
925
3
27
8
6 7
145 0
923
2
6 7
145 0
983
28
2
6 7
145 0
983
2
7
6 2
145 0
983
29
• Tiếp tục thực hiện cho đến khi dãy có thứ tự
3
6 2
145 0
987
30
Giải thuật biến đổi heap max (q, r)1. Khởi tạo
– x = aq
– i=q– j=2i– cont=true
2. Khi (j<=r) Λ cont, thực hiện:2.1 Nếu (j<r) Λ (aj<aj+1) thì j=j+12.2 Nếu x<aj thì– ai = aj
– i=j– j=2i2.3 Ngược lại– cont = False
3. ai=x
31
Sắp thứ tự1. Khởi tạo heap max ban đầu
Với i=n/2, …, 1. Thực hiện:
Biến đổi heap max(i, n)
2. Sắp thứ tự
– i=n
– Lặp
• Hoán đổi a1 với ai
• i = i-1
• Biến đổi heap max(1, i)
– Cho đến khi i=1
32
void sift(elem a[ ], int q, int r, int (*comp)(elem, elem)){
elem x;int i, j, cont =1, sz = sizeof(elem);i = q;j = 2*i+1; //lưu ýmemcpy(&x, &a[i], sz);while (j<=r && cont){
if (j<r && comp(a[j], a[j+1])<0) j++;if (comp(x, a[j]) <0){
memcpy(&a[i], &a[j], sz);i = j;j = 2*i+1; //lưu ý
}else
cont = 0;}memcpy(&a[i], &x, sz);
}
33
Hàm Heapsortvoid heapsort(elem a[ ], int n, int (*comp)(elem, elem)){
int i, sz = sizeof(elem);elem x;for (i=n/2-1; i>=0; i--) //lưu ý n/2-1 và 0
sift(a, i, n-1, comp);i = n-1;do {
memcpy(&x, &a[0], sz); //lưu ý a[0]memcpy(&a[0], &a[i], sz);memcpy(&a[i], &x, sz);i--;sift(a, 0, i, comp); //0
} while (i>0);}
34
2. Giải thuật Quick sort• Cải tiến từ phương pháp đổi chổ• Dựa trên phép phân hoạch:• Chọn giá trị phân hoạch x thỏa:
Min { ai } ≤ x ≤ Max { ai }
– Dò tìm từ trái (l) qua phải phần tử ai ≥ x
– Dò tìm từ phải (r) qua trái phần tử aj ≤ x
– Nếu i < j thì hoán đổi ai với aj
• Tiếp tục thực hiện cho đến khi i>jKết quả dãy sẽ bị phân hoạch thành 2 dãy:
Dãy từ l đến j mang giá trị ≤ x
Dãy từ i đến r mang giá trị ≥ x
• Để sắp thứ tự ta tiếp tục phân hoạch trên 2 đoạn (l,j) và (i, r)
35
void sort(elem a[ ], int l, int r, int (*comp)(elem, elem)){
static elem x, t;int i, j, sz = sizeof(elem);i = l;j = r;memcpy(&x, &a[(l+r)/2], sz);do {
while (comp(a[i], x)<0) i++;while (comp(a[j], x)>0) j--;if (i<=j){
memcpy(&t, &a[i], sz);memcpy(&a[i], &a[j], sz);memcpy(&a[j], &t, sz);i++;j--;
}} while (i<=j);if (l<j) sort(a, l, j, comp);if (i<r) sort(a, i, r, comp);
}
36
void qsort(elem a[ ], int n, int (*comp)(elem, elem))
{
sort(a, 0, n-1, comp);
}
37
Bài tập
• Viết– Quick sort 1 lời gọi đệ quy– Quick sort không đệ quy– Chương trình nhập 1 dãy số nguyên, đưa:
• Lẻ về đầu dãy và sắp thứ tự tăng • Chẵn về cuối dãy và sắp thứ tự giảm