370 likes | 508 Views
Sắp thứ tự. 1. Phương pháp chèn (Insertion sort). Nội dung phương pháp: Xét dãy a 1 , …., a i-1 có thứ tự, tìm vị trí thích hợp của a i trong dãy trên để chèn vào sao cho ta được dãy a 1 , …., a i có thứ tự. Thực hiện với i = 2, ….., n ta được dãy a 1 , …., a n có thứ tự. Ví dụ.
E N D
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ự
Giải thuật chèn • Thực hiện với i=2 , …, n: • x = ai • j = i-1 • Khi (j>0) Λ (x<aj) 3. 1 aj+1=aj 3. 2 j = j-1 • aj+1=x
Độ phức tạp • Số phép gán: • Số phép so sánh:
Cài đặt void 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); } }
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ự
Giải thuật chọn • Với i=1 , …, n-1, thực hiện: • k=i • x = ak • Với j = i+1, …, n, thực hiện: Nếu x>aj • k=j • x=ak • ak = ai • ai=x
Độ phức tạp • Số phép gán: • Số phép so sánh:
Cài đặt void 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); } }
Cài đặt void 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); } }
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
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
Sap thu tu - phuong phap noi bot void 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); } }
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);
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
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); Thuật giải Shaker sort(C)
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ụ:
9 6 8 0 3 7 5 2 1 4 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ụ:
a1 a2 a3 a4 a5 a6 a7 a1 a3 a2 a6 a7 a4 a5 a8 a9 a10 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 a3 a2 a6 a7 a4 a5 a8 a9 a10 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
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 đổia1 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ự
4 9 7 7 9 8 1 1 0 0 6 6 8 4 5 5 2 2 3 3 Giải thuật biến đổi heap max (q, r) 4
9 3 7 7 8 8 1 1 0 0 6 6 4 4 5 5 2 2 3 9 3
8 2 7 7 6 6 1 1 0 0 5 5 4 4 3 3 2 8 9 9
2 7 7 2 6 6 1 1 0 0 5 5 4 4 3 3 8 8 9 9 2
3 2 6 1 0 5 4 7 8 9 • Tiếp tục thực hiện cho đến khi dãy có thứ tự
Giải thuật biến đổi heap max (q, r) • Khởi tạo • x = aq • i=q • j=2i • cont=true • Khi (j<=r) Λ cont, thực hiện: 2.1 Nếu (j<r) Λ (aj<aj+1) thì j=j+1 2.2 Nếu x<aj thì • ai = aj • i=j • j=2i 2.3 Ngược lại • cont = False • ai=x
Sắp thứ tự • 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) • 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
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); }
Hàm Heapsort void 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); }
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>j Kế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)
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); }
void qsort(elem a[ ], int n, int (*comp)(elem, elem)) { sort(a, 0, n-1, comp); }
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