Bài giảng Cấu trúc dữ liệu 1 - Chương 2: Tìm kiếm và sắp xếp
Mục tiêu:
• Giới thiệu một số thuật toán tìm kiếm và sắp xếp nội.
• Phân tích, đánh giá độ phức tạp của các giải thuật tìm
kiếm, sắp xếp.
Nội dung:
• Nhu cầu tìm kiếm và sắp xếp dữ liệu trong một hệ
thống thông tin.
• Các giải thuật tìm kiếm nội.
• Các giải thuật sắp xếp nội.
Only one subarray 162 2 4 5 6 8 12 151 2 3 4 5 6 7 81 Merge sort – Ví dụ 163 Merge Sort – Cài đặt • Dữ liệu hỗ trợ: 2 mảng b, c: int 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); 164 Merge sort – Cài đặt //khai báo 2 mảng phụ 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); } } 165 Merge sort – Cài đặt 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<N) && (i<k); i++, pa++, pb++) b[pb] = a[pa]; for (i=0; (pa<N) && (i<k); i++, pa++, pc++) c[pc] = a[pa]; } nb = pb; nc = pc; } 166 Merge sort – Cài đặt 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 ++]; } 167 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 ++]; } 168 Merge Sort – Đánh giá giải thuật Giải thuật trộn trực tiếp là phương pháp trộn đơn giản nhất: • Việc phân hoạch thành các dãy con chỉ là tách dãy thành các dãy con không giảm độ dài k. • Độ dài của dãy con là 1, 2, 4, 8, … đảm bảo dãy con luôn là dãy con không giảm sau mỗi bước tách - trộn. • Không sử dụng thông tin về thứ tự của dãy ban đầu 2 hệ quả: – Độ phức tạp thuật toán không phụ thuộc vào dãy ban đầu. – Một dãy con không giảm đang có sẵn bị chia nhỏ thành các dãy không cần thiết cải tiến thành thuật toán: Trộn tự nhiên (Natural Merge sort). 169 • Số lần thực hiện việc chia luân phiên và trộn: Sau mỗi lần tách – trộn, độ dài K của dãy con tăng gấp đôi Số lần tách – trộn trong thuật toán: log2n . • Chi phí thực hiện tách - trộn tỉ lệ thuận với n. Chi phí thực hiện của giải thuật MergeSort là O(nlog2n). Merge Sort – Đánh giá giải thuật 170 • Một nhược điểm lớn nữa của các thuật toán trộn là khi cài đặt thuật toán đòi hỏi thêm không gian bộ nhớ để lưu các dãy phụ b, c. • Hạn chế này khó chấp nhận trong thực tế vì các dãy cần sắp xếp thường có kích thước lớn. • Vì vậy thuật toán trộn thường được dùng để sắp xếp các cấu trúc dữ liệu khác phù hợp hơn như danh sách liên kết hoặc file. Merge Sort – Đánh giá giải thuật 171 Sắp xếp theo phương pháp trộn trực tiếp Thuật toán trộn tự nhiên Natural Merge sort • Một đường chạy của dãy số a là một dãy con không giảm của cực đại của a. Nghĩa là, đường chạy r = (ai, ai+1, …, aj) phải thỏa điều kiện: • Ví dụ dãy 12, 2, 8, 5, 1, 6, 4, 15 có thể coi như gồm 5 đường chạy (12); (2, 8); (5); (1, 6); (4, 15). ⎪⎩ ⎪⎨ ⎧ > < ∈∀≤ + − + 1 1 1 ),[ jj ii kk aa aa jikaa 172 Sắp xếp theo phương pháp trộn trực tiếp Thuật toán trộn tự nhiên Natural Merge sort • Thuật toán trộn tự nhiên khác thuật toán trộn trực tiếp ở chỗ thay vì luôn cứng nhắc phân hoạch theo dãy con có chiều dài k, việc phân hoạch sẽ theo đơn vị là đường chạy. ta chỉ cần biết số đường chạy của a sau lần phân hoạch cuối cùng là có thể biết thời điểm dừng của thuật toán vì dãy đã có thứ tự là dãy chi có một đường chạy. 173 Sắp xếp theo phương pháp trộn trực tiếp Thuật toán trộn tự nhiên Natural Merge sort • Bước 1 : // Chuẩn bị – r = 0; // r dùng để đếm số dường chạy • Bước 2 : Tách dãy a1, a2, …, an thành 2 dãy b, c theo nguyên tắc luân phiên từng đường chạy: – Bước 2.1 : • Phân phối cho b một đường chạy; r = r+1; • Nếu a còn phần tử chưa phân phối – Phân phối cho c một đường chạy; r = r+1; – Bước 2.2 : • Nếu a còn phần tử: quay lại bước 2.1; • Bước 3 : – Trộn từng cặp đường chạy của 2 dãy b, c vào a. • Bước 4 : – Nếu r <= 2 thì trở lại bước 2; Ngược lại: Dừng. Sắp xếp theo phương pháp Cơ số Radix Sort 175 Sắp xếp theo phương pháp cơ số Radix Sort • Radix Sort là một thuật toán tiếp cận theo một hướng hoàn toàn khác. • Nếu như trong các thuật toán khác, cơ sở để sắp xếp luôn là việc so sánh giá trị của 2 phần tử thì Radix Sort lại dựa trên nguyên tắc phân loại thư của bưu điện. Vì lý do đó Radix Sort còn có tên là Postman’s sort. • Radix Sort không hề quan tâm đến việc so sánh giá trị của phần tử mà bản thân việc phân loại và trình tự phân loại sẽ tạo ra thứ tự cho các phần tử. 176 Sắp xếp theo phương pháp cơ số Radix Sort • Để chuyển một khối lượng thư lớn đến tay người nhận ở nhiều địa phương khác nhau, bưu điện thường tổ chức một hệ thống phân loại thư phân cấp. • Trước tiên, các thư đến cùng một tỉnh, thành phố sẽ được sắp chung vào một lô để gửi đến tỉnh thành tương ứng. • Bưu điện các tỉnh thành này lại thực hiện công việc tương tự. Các thư đến cùng một quận, huyện sẽ được xếp vào chung một lô và gửi đến quận, huyện tương ứng. • Cứ như vậy, các bức thư sẽ được trao đến tay người nhận một cách có hệ thống mà công việc sắp xếp thư không quá nặng nhọc. 177 Sắp xếp theo phương pháp cơ số Radix Sort • Mô phỏng lại qui trình trên, để sắp xếp dãy a1, a2, ..., an, giải thuật Radix Sort thực hiện như sau: – Trước tiên, ta có thể giả sử mỗi phần tử ai trong dãy a1, a2, ..., an là một số nguyên có tối đa m chữ số. – Ta phân loại các phần tử lần lượt theo các chữ số hàng đơn vị, hàng chục, hàng trăm, … tương tự việc phân loại thư theo tỉnh thành, quận huyện, phường xã, …. 178 Sắp xếp theo phương pháp cơ số Radix Sort • Bước 1 :// k cho biết chữ số dùng để phân loại hiện hành – k = 0; // k = 0: hàng đơn vị; k = 1: hàng chục; … • Bước 2 : //Tạo các lô chứa các loại phần tử khác nhau – Khởi tạo 10 lô B0, B1, …, B9 rỗng; • Bước 3 : – For i = 1 .. n do • Đặt ai vào lô Bt với t: chữ số thứ k của ai; • Bước 3 : – Nối B0, B1, …, B9 lại (theo đúng trình tự) thành a. • Bước 4 : – k = k+1;Nếu k < m thì trở lại bước 2. Ngược lại: Dừng 179 Sắp xếp theo phương pháp cơ số Radix Sort 180 Sắp xếp theo phương pháp cơ số Radix Sort 181 Sắp xếp theo phương pháp cơ số Radix Sort 182 Sắp xếp theo phương pháp cơ số Radix Sort 183 Sắp xếp theo phương pháp cơ số Radix Sort 184 Sắp xếp theo phương pháp cơ số Radix Sort • Đánh giá giải thuật: – Với một dãy n số, mỗi số có tối đa m chữ số, thuật toán thực hiện m lần các thao tác phân lô và ghép lô. – Trong thao tác phân lô, mỗi phần tử chỉ được xét đúng một lần, khi ghép cũng vậy. – Như vậy, chi phí cho việc thực hiện thuật toán hiển nhiên là O(2mn) = O(n). 185 Sắp xếp theo phương pháp cơ số Radix Sort Nhận xét: – Sau lần phân phối thứ k các phần tử của A vào các lô B0, B1, …, B9, và lấy ngược trở ra, nếu chỉ xét đến k+1 chữ số của các phần tử trong A, ta sẽ có một mảng tăng dần nhờ trình tự lấy ra từ 0 → 9. Nhận xét này bảo đảm tính đúng đắn của thuật toán. – Thuật toán có độ phức tạp tuyến tính nên hiệu quả khi sắp dãy cố rất nhiều phần tử, nhất là khi khóa sắp xếp không quá dài so với số lượng phần tử (điều này thường gặp trong thực tế). 186 Sắp xếp theo phương pháp cơ số Radix Sort Nhận xét: – Thuật toán không có trường hợp xấu nhất và tốt nhất. Mọi dãy số đều được sắp với chi phí như nhau nếu chúng có cùng số phần tử và các khóa có cùng chiều dài. – Thuật toán cài đặt thuận tiện với các mảng với khóa sắp xếp là chuỗi (ký tự hay số) hơn là khóa số như trong ví dụ do tránh được chi phí lấy các chữ số của từng số. 187 Sắp xếp theo phương pháp cơ số Radix Sort Nhận xét: – Số lượng lô lớn (10 khi dùng số thập phân, 26 khi dùng chuỗi ký tự tiếng Anh, …) nhưng tổng kích thước của tất cả các lô chỉ bằng dãy ban đầu nên ta không thể dùng mảng để biểu diễn B. Như vậy, phải dùng cấu trúc dữ liệu động để biểu diễn B ⇒ Radix Sort rất thích hợp cho sắp xếp trên danh sách liên kết. 188 Sắp xếp theo phương pháp cơ số Radix Sort Nhận xét: – Người ta cũng dùng phương pháp phân lô theo biểu diễn nhị phân của khóa sắp xếp. Khi đó ta có thể dùng hoàn toàn cấu trúc dữ liệu mảng để biểu diễn B vì chỉ cần dùng hai lô B0 và B1. Tuy nhiên, khi đó chiều dài khóa sẽ lớn. Khi sắp các dãy không nhiều phần tử, thuật toán Radix sort sẽ mất ưu thế so với các thuật toán khác.
File đính kèm:
- Bài giảng Cấu trúc dữ liệu 1 - Chương 2 Tìm kiếm và sắp xếp.pdf