Cấu trúc dữ liệu và giải thuật I - Bài 9 docx

13 276 0
Cấu trúc dữ liệu và giải thuật I - Bài 9 docx

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

Thông tin tài liệu

Bài Sắp xếp danh sách Mục tiêu  Giới thiệu thuật toán xếp phù hợp với danh sách liên kết Nội dung  Các cách tiếp cận  Một số thuật toán hiệu qủa o Quicksort o Merge sort o Radix sort Bài tập   Bài tập lý thuyất Bài tập thực hành I Các cách tiếp cận Một danh sách có thứ tự (danh sách sắp) danh sách mà phần tử xếp theo thứ tự dựa trường khố Ví dụ, danh sách phần tử số có thứ tự tăng danh sách mà với cặp phần tử X, Y ta ln có XY X xuất trước Y danh sách (danh sách có khơng có phần tử xem danh sách sắp) Ðể xếp danh sách, ta thực phương án sau:  Phương án 1: Hoán vị nội dung phần tử danh sách (thao tác vùng Info) Với phương án này, chọn thuật tốn xếp biết để cài đặt lại xâu thực mảng, điểm khác biệt cách thức truy xuất đến phần tử xâu thông qua liên kết thay số mảng Do dựa việc hoán vị nội dung phần tử, phương pháp đòi hỏi sử dụng thêm vùng nhớ trung gian nên thích hợp với xâu có phần tử có thành phần Info kích thước nhỏ Hơn số lần hốn vị lên đến bậc n2 với xâu n phần tử Khi kích thước trường Info lớn, việc hốn vị giá trị hai phân tử chiếm chi phí đáng kể Ðiều làm cho thao tác xắp xếp chậm lại Như vậy, phương án không tận dụng ưu điểm xâu Ví dụ : Cài đặt thuật toán xếp Chọn trực tiếp xâu : void { ListSelectionSort (LIST &l) NODE *min; // đến phần tử có giá trị nhỏ xâu NODE p = l.pHead; while(p != l.pTail) { q = p->pNext; = p; while(q != NULL) {if(q->Info< min->Info ) = q; // ghi nhận vị trí phần tử hành q q= q->pNext;} // Hoán vị nội dung phần tử Hoanvi(min->Info, p->Info]); p = p->pNext; } } *p,*q;  Phương án 2: Thay đổi mối liên kết (thao tác vùng Next) Do nhược điểm phương pháp xếp theo phương án 1, liệu lưu phần tử xâu có kích thước lớn người ta thường dùng cách tiếp cận khác Thay hốn đổi giá trị, ta tìm cách thay đổi trình tự móc nối phần tử cho tạo lập nên thứ tự mong muốn Cách tiếp cận cho phép ta thao tác móc nối (trường pNext) Như ta biết, kích thước trường không phụ thuộc vào chất liệu lưu xâu có trỏ (2 byte byte môi trường 16 bit byte byte môi trường 32 bit, ) Tuy nhiên thao tác mọc nối thường phức tạp thao tác trực tiếp liệu Vì vậy, ta cần cân nhắc kỹ lưỡng trước chọn cách tiếp cận Nếu dũ liệu không lớn ta nên chọn phương án thuật tốn hiệu Một cách thay đổi móc nối đơn giản tạo danh sách danh sách có thứ tự từ danh sách cũ (đồng thời hủy danh sách cũ) Giả sử danh sách quản lý trỏ đầu xâu Result, ta có phương án thuật toán chọn trực tiếp sau :      Bước1: Bước2: Bước3: Bước4: Bước5: Khởi tạo danh sách Result rỗng; Tìm danh sách cũ l phần tử nhỏ nhất; Tách khỏi danh sách l; Chèn vào cuối danh sách Result; Lặp lại bước chưa hết danh sách Head; Ta cài đặt thuật tốn sau: void { ListSelectionSort2 (LIST &l) LIST lRes; NODE xâu *min; // đến NODE *p,*q, minprev; phần tử có giá trị nhỏ lRes.pHead = lRes.pTail = NULL; // khởi tạo lRes while(l.pHead != NULL) { p = l.pHead; q = p->pNext; = p; minprev = NULL; while(q != NULL) { if(q->Info< min->Info ) { = q; minprev = p } p = q; q = q->pNext; } if(minprev != NULL) minprev->pNext = min->pNext; else l.pHead = min->pNext; min->pNext = NULL; AddTail(lRes, min); } l = lRes; } II Một số thuật toán xếp hiệu xâu Thuật toán Quick Sort Trong số thuật tốn xếp, có lẽ tiếng hiệu thuật toán Quick Sort Các cài đặt thuật toán thường thấy cấu trúc liệu mảng Trong chương khảo sát thuật tốn Tuy nhiên để ý thuật tốn xếp hiệu xâu Hơn nữa, cài đặt xâu, chất thuật toán thể cách rõ ràng hết:  Thuật toán Quick Sort: Bước 1: Chọn X phần tử đầu xâu L làm phần tử cầm canh Loại X khỏi L Bước 2: Tách xâu L làm xâu L1 (gồm phần tử nhỏ hay X) L2 (gồm phần tử lớn X) Bước 3: Nếu L1 != NULL Quick Sort (L1) Bước 4: Nếu L2 != NULL Quick Sort (L2) Bước 5: Nối L1, X, L2 lại theo trình tự ta có xâu L xếp  Ví dụ Cho dãy số a: Chọn X = làm phần tử cầm canh tách l thành l1, l2: Sắp xếp l1: Sắp xếp l2: Chọn X = làm phần tử cầm canh tách l2 l21, l22: Nối l12, X2, l22 thành l2: Nối l1, X, l2 thành l:  Cài đặt : void ListQSort(LIST & l) { NODE *p, *X; LIST l1, l2; // X đến phần tử cầm canh if(l.pHead == l.pTail) return;//đã có thứ tự l1.pHead == l1.pTail = NULL; //khởi tạo l2.pHead == l2.pTail = NULL; X = l.pHead; l.pHead = X->pNext; while(l.pHead != NULL) //Tách l thành l1, l2; { p = l.pHead; l.pHead = p->pNext; p->pNext = NULL; if (p->Info Info) AddTail(l1, p); else AddTail(l2, p); } ListQSort(l1); //Gọi đệ qui để sort l1 ListQSort(l2); //Gọi đệ qui để sort l2 //Nối l1, X l2 lại thành l xếp if(l1.pHead != NULL) { l.pHead = l1.pHead; l1.pTail->pNext = X; } else l.pHead = X; X->pNext = l2; if(l2.pHead != NULL) l.pTail = l2.pTail; else l.pTail = X; } Như thấy, Quick sort xâu đơn đơn giản phiên mảng chiều nhiều Hãy cài đặt thử thuật toán bạn thấy hiệu khó có thuật toán sánh Một điều đáng lưu ý khí dùng quick sort xếp xâu đơn, ta có chọn lựa phần tử cầm canh hợp lý phân tử đầu xâu Chọn phần tử khác làm tăng chi phí cách khơng cần thiết cấu trức tự nhiên xấu Thuật toán Merge Sort Cũng thuật toán Quick Sort, Merge sort thuật toán xếp hiệu xâu Cài đặt thuật toán cấu trúc liệu mảng rắc rối bạn thấy chương Người ta hay nhắc đến Merge Sort thuật toán xếp file (sắp xếp ngoài) Cũng Quick Sort, cài đặt xâu, chất thuật toán thể rõ ràng:  Thuật toán Merge Sort: Bước 1: Phân phối luân phiên đường chạy xâu L vào xâu L1 L2 Bước 2: Nếu L1 != NULL Merge Sort (L1) Bước 3: Nếu L2 != NULL Merge Sort (L2) Bước 4: Trộn L1 L2 xếp lại ta có xâu L xếp  Ví dụ Cho dãy số a: Phân phối đường chạy l vào l1, l2: Sắp xếp l1: Phân phối đường chạy l1 vào l11, l12: Trộn l11, l12 lại thành l1: Sắp xếp l2: Phân phối đường chạy l2 vào l21, l22: Trộn l11, l12 lại thành l2: Trộn l1, l2 lại thành l:  Cài đặt : void ListMergeSort(LIST & l) { LIST l1, l2; if(l.pHead == l.pTail) return;//đã có thứ tự l1.pHead == l1.pTail = NULL; //khởi tạo l2.pHead == l2.pTail = NULL; //Phân phối l thành l1 l2 theo đưòng chạy DistributeList(l, l1, l2); ListMergeSort(l1); //Gọi đệ qui để sort l1 ListMergeSort(l2); //Gọi đệ qui để sort l2 //Trộn l1 l2 có thứ tự thành l MergeList(l, l1, l2); } Trong đó, hàm DistributeList MergeList viết sau: void DistributeList(LIST& l,LIST& l1,LIST& l2) { NODE *p; //Tách l thành l1, l2; { p = l.pHead; l.pHead = p->pNext; p->pNext = NULL; AddTail(l1, p); }while((l.pHead)&&(p->InfoInfo)); if(l.pHead) DistributeList(l, l2, l1); else l.pTail = NULL; } void MergeList(LIST& l,LIST& l1,LIST& l2) { NODE *p; while((l1.pHead)&&(l2.pHead)) { if(l1.pHead->Info Info) { p = l1.pHead; l1.pHead = p->pNext; } else { p = l2.pHead; l2.pHead = p->pNext; } p->pNext = NULL; AddTail(l, p); }; if(l1.pHead) {//Nối phần lại l1 vào cuối l l.pTail->pNext = l1.pHead; l.pTail = l1.pTail; } else if(l2.pHead) {//Nối phần lại l2 vào cuối l l.pTail->pNext = l2.pHead; l.pTail = l2.pTail; } } Như thấy, Merge sort xâu đơn đơn giản phiên mảng chiều Một điều đáng lưu ý khí dùng Merge sort xếp xâu đơn, ta không cần dùng thêm vùng nhớ phụ cài đặt mảng chiều Ngoài ra, thủ tục Merge xâu khơng phức tạp mảng ta phải trộng hai xâu có thứ tự, mảng ta phải trộn hai mảng Thuật toán Radix Sort Thuật toán Radix Sort giới thiệu chương Khi cài đặt cấu trúc liệu mảng chiều, thuật toán gặp hạn chế lớn đòi hỏi thêm nhiều nhớ Trong chương 2, đề cập đến khả cài đặt danh sách liên kết thuật toán Sau chi tiết thuật toán:  Thuật toán Radix Sort: Bước 1: Khởi tạo danh sách (lô) rỗng B0, B1, , B9?; k = 0; Bước 2: Trong L khác rỗng: B21: p = L.pHead; L.pHead->pNext; B22: Ðặt phần tử p vào cuối lô Bd với d chữ số thứ k L.pHead->Info; Bước 3: Nối B0, B1, , B9? lại thành L; Làm B0, B1, , B9; Bước 4: k = k+1; Nếu k < m: quay lại Bước  Cài đặt : void ListRadixSort(LIST & l, int m) { LIST B[10]; NODE int *p; i, k; if(l.pHead == l.pTail) return;//đã có thứ tự for(i = 0; i < 10; i++) B[i].pHead = B[i].pTail = NULL; for(k = 0; k < 10; k++) { while(l.pHead) { p = l.pHead; l.pHead = p->pNext; p->pNext = NULL; i = GetDigit(p->Info, k); AddTail(B[i], p); } l = B[0]; for(i = 1; i < 10; i++) AppendList(l, B[i]);//Nối B[i] vào cuối l } } Trong đó, hàm AppendList GetDigit viết sau: void AppendList(LIST& l,LIST& l1) { if(l.pHead) { l.pTail->pNext = l1.pHead; l.pTail = l1 pTail; } else //xâu l rỗng l = l1; } int GetDigit(unsign long N, int k) { switch(k) { } } case 0: return (N % 10); case 1: return ((N/10) % 10); case 2: return ((N/100) % 10); case 3: return ((N/1000) % 10); case 4: return ((N/10000) % 10); case 5: return ((N/100000) % 10); case 6: return ((N/1000000) % 10); case 7: return ((N/10000000) % 10); case 8: return ((N/100000000) % 10); case 9: return ((N/1000000000) % 10); ... thứ tự, mảng ta ph? ?i trộn hai mảng Thuật toán Radix Sort Thuật toán Radix Sort gi? ?i thiệu chương Khi c? ?i đặt cấu trúc liệu mảng chiều, thuật tốn gặp hạn chế lớn đ? ?i h? ?i thêm nhiều nhớ Trong chương... = p->pNext; = p; minprev = NULL; while(q != NULL) { if(q->Info< min->Info ) { = q; minprev = p } p = q; q = q->pNext; } if(minprev != NULL) minprev->pNext = min->pNext; else l.pHead = min->pNext;... { while(l.pHead) { p = l.pHead; l.pHead = p->pNext; p->pNext = NULL; i = GetDigit(p->Info, k); AddTail(B [i] , p); } l = B[0]; for (i = 1; i < 10; i+ +) AppendList(l, B [i] );//N? ?i B [i] vào cu? ?i l

Ngày đăng: 22/07/2014, 14:21

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan