Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.66 MB, 17 trang )
<span class="text_page_counter">Trang 1</span><div class="page_container" data-page="1">
ĐẠI HỌC QUỐC GIA THÀNH PHỐ HỒ CHÍ MINH TRƯỜNG ĐẠI HỌC KHOA HỌC TỰ NHIÊN
KHOA CÔNG NGH THÔNG TIN Ệ
MƠN H C: C U TRÚC DỌ Ấ Ữ LIỆU VÀ GI I THU T Ả Ậ GIẢNG VIÊN:NGUYỄN TR N DUY MINH Ầ
Thành ph H Chí Minh - 2022ố ồ
<small>MỤC LỤ ... 1 C</small>
<small>I. VỀ CÁC THUẬT TOÁN VÀ ĐỘ PHỨC TẠP CỦA CHÚNG. ... 2 </small>
<small>1.1.Thuật toán Selection Sort ... 2 </small>
<small>1.2.Thuật toán Insertion Sort ... 2 </small>
<small>1.3.Thuật toán Bubble Sort ... 3 </small>
<small>1.4.Thuật toán Shell Sort ... 4 </small>
<small>1.5.Thuật toán Heap Sort ... 5 </small>
<small>1.6.Thuật toán Merge Sort ... 7 </small>
<small>1.7.Thuật toán Quick Sort ... 9 </small>
<small>1.8.Thuật toán Radix Sort ... 10 </small>
<small>II. THỰC NGHI M CÁC THU T TOÁNỆẬ ... 13</small>
<small>1. Đối v i các m ng s p x p ng u nhiênớảắếẫ ... 13 </small>
<small>2. Đối v i thu t toán gớậần như được sắp xếp tăng dần ... 14</small>
<small>3. Đối v i mớảng đã được sắp xếp tăng dần ... 15 </small>
<small>4. Đối v i mớảng được sắp x p gi m dếảần ... 16</small>
</div><span class="text_page_counter">Trang 3</span><div class="page_container" data-page="3">1.1. Thuật toán Selection Sort
- Ý tưởng: thu t toán s p x p Selection Sort là mậ ắ ế ột thuật toán s p x p các mắ ế ảng bằng cách đi tìm phần tử có giá trị nhỏ nhất trong đoạn và thay đổi chúng v i ph n ớ ầ tử ở đoạn đầu đoạn chưa được sắp x p. T i mế ạ ỗi bướ ặc l p c a thu t toán, ph n t nhủ ậ ầ ử ỏ nhất c a mủ ảng con chưa đượ ắc s p x p sế ẽ được di chuy n vể ề đoạn đã đượ ắc s p xế p. - Về code (hàm Swap mặc định đã đượ ử ục s d ng và chèn vào mã nguồn):
void SelectionSort(int a[], int n){
//nếu như phần tử ứth j nh ỏhơn phần tử ứ min_idx thì gán th min_idx = j và đổi chỗ phần tử nhỏ nhất với
phần tử đầu tiên
if (a[j]< a[min_idx]) min_idx=j; if( min_idx!=i) Swap(a[min_idx],a[i ]); }
}
- Về độ ph c t p: ứ ạ
Thời gian: vì thu t tốn Selection Sort có hai phép l p lòng vào nhau ậ ặ với m i phép lỗ ặp là n bước nên về ph c t p v độ ứ ạ ề thời gian là:O(n*n) = O(n <small>2</small>).
Khơng gian: vì các mảng là như nhau sau mỗi bước nên độ ph c tứ ạp về không gian là O(1).
1.2. Thuật toán Insertion Sort
- Ý tưởng: Thuật toán Insertion Sort là 1 trong những thuật toán dễ thực hiện nhất và phù h p v i các dợ ớ ữ liệu có độ lớn nh . Vỏ ề thuật tốn, chúng ta xem nó như việc s p x p m t bắ ế ộ ộ bài tây, đầu tiên ta cho lá bài đầu tiên làm gốc, đánh d u lá bài ấ thứ 2 và so sánh độ lớn v i lá bài th nh t, n u nhớ ứ ấ ế ỏ hơn thì ta sẽ thay đổ ịi v trí 2 lá
</div><span class="text_page_counter">Trang 4</span><div class="page_container" data-page="4">bài, n u khơng thì ta gi nguyên và chuy n d u cho lá bài tiế ữ ể ấ ếp theo cho đến lá cuối cùng. Cũng như vậy, thuật toán Insertion Sort cũng duyệt
void InsertionSort(int a[], int n){
//tạo vòng l p duy t m ng và cho ph n tặ ệ ả ầ ử thứ 2 làm g c ố for (int i=1;i<=n;i++){
int key=a[i];
j=i-1;//j là bi n duy t qua các mế ệ ảng đã được sắp xếp //Di chuy n m ng a[0,..i-1], lể ả ớn hơn phầ ửn t key lùi v phía ề
while(j>=0 && a[j]>a[key]){
Thời gian: tương tự như Selection Sort là O(n<small>2</small>). Không gian: tương tự như Selection Sort là O(1). 1.3. Thuật toán Bubble Sort
- Ý tưởng: Thuật toán Bubble Sort hoạt động như việc chỉnh đốn hang ngũ trong hang, ta so sánh chi u cao c a 2 cá nhân trong hàng, n u b n bên ph i thề ủ ế ạ ả ấp hơn thì ta đổi chỗ 2 bạn cho nhau và tiếp tục như thế. Trong lập trình, ta duyệt 1 mảng và đưa các số lớn nhất dần về phía dưới bằng cách so sánh 2 ph n t t ng cầ ử ừ ặp với nhau, n u ph n tế ầ ử bên ph i nhả ỏ hơn phầ ử bên trái thì ta ti p tn t ế ục đổi chỗ hoặc không đổi chỗ nếu chúng đã theo thứ tự và tiếp tục xét tiếp cặp tiếp theo,như thế, phần tử nhỏ hơn sẽ "nổi" lên, còn ph n tầ ử lớn hơn sẽ "chìm" d n và v bên phầ ề ải, đó là lý do vì sao thu t tốn tên là Bubble Sort. C p tậ ứ tiế ục cho đến khi ph n t l n nhầ ử ớ ất được đưa về cuối và ta xét ti p vòng th hai, th ế ứ ứ ba,.. cho đến khi mảng đã được sắp xếp hoàn toàn.
</div><span class="text_page_counter">Trang 5</span><div class="page_container" data-page="5">void BubbleSort(int a[], int n){ int temp;
//ta duy t vào m ng v i vệ ả ớ ị trí đầu tiên là 0 for (int i = 0; i < n; i++){
//ta duy t m ng l n thệ ả ầ ứ 2 để ắ ặ b t c p v i ph n tớ ầ ử đầu tiên để so sánh và đổi ch vỗ ới
Thời gian:tương tự như 2 thuật toán trên là O(n <small>2</small>). Khơng gian:tương tự như 2 thuật tốn trên là O(1). 1.4. Thuật toán Shell Sort
- Ý tưởng: Shell Sort cũng có ý tưởng hoạt động tương tự như thuật toán Insertion Sort, th m chí cịn là b n nâng c p c a Insertion Sort nh m tránh vi c tráo ậ ả ấ ủ ằ ệ đổi v trí c a 2 ph n tị ủ ầ ử cách xa nhau b ng cách so sánh các ph n t ằ ầ ử ở các kho ng(gap ả hay interval) v i các kho ng nh n giá trớ ả ậ ị là n/2, n/4, n/8,… cho đến khi các kho ng ả bằng 1. Gi i thu t khá hi u qu v i các dả ậ ệ ả ớ ữ liệu có độ ớn trung bình và có độ l phức tạp trung bình nhỏ hơn rất nhi u so v i thu t toán Insertion Sort. ề ớ ậ
</div><span class="text_page_counter">Trang 6</span><div class="page_container" data-page="6">void ShellSort(int a[], int n){
//tạo vòng l p v i biặ ớ ến interval để chia m ng ra thành các khoả ảng để so sánh
for(int interval = n/2 ; interval >0; interval/=2){
//tạo vòng l p cho bi n i ch y trong khoặ ế ạ ảng đã được chia để ến hành Insertion ti Sort cho kho ng ả
for(int i= interval; i<n;i++){
temp =a[i];//lưu các giá trị trong khoảng vào biến tạm để lưu giá trị vào v ị trí chuẩn khi s p x p ắ ế
//cho bi n j ch y trong khoế ạ ảng để tìm v trí chính xác cho giá trị ị a[i] for (int j=i, j>=interval && a[j-interval] > temp; j-=interval){
Thời gian: độ phức tạp của thuật toán Shell Sort phụ thuộc vào việc kho ng ả chia c a b n cho thu t toán ủ ạ ậ như thế nào. Nếu trong trường hợp tốt nhất, khi mà mảng đã được s p x p thì tắ ế ổng độ chia c a thu t toán bủ ậ ằng đúng dữ liệu của mảng, độ ph c t p c a Shell Sort là O(n*logứ ạ ủ <small>2</small>(n)) còn trong trường hợp xấu nh t, thu t tốn Shell Sort sấ ậ ẽ có độ ph c tứ ạp tương tự hư Insertion Sort n là O(n ), và trung bình thu t tốn nh<small>2</small> ậ ận độ ph c t p là O(n*ứ ạ log<small>2</small>(n) ).<small>2</small> Khơng gian: O(1).
1.5. Thuật tốn Heap Sort
- Ý tưởng: Thuật toán Heap Sort là thuật toán được dựa trên cấu trúc dữ liệu cây nh phân Binary Heap. Thu t toán giúp s p x p các ph n t l n nh t trong danh ị ậ ắ ế ầ ử ớ ấ sách về cuố ữ liệi d u v i tớ ốc độ chạy nhanh và cài đặt không quá ph c t p. Thuứ ạ ật toán Heap Sort thường sẽ sử dụng cấu trúc dữ liệu Max heap là chủ yếu với phần t ử lớn nh t s luôn là nút còn các ph n tấ ẽ ầ ử nh nh t sỏ ấ ẽ là lá, điều này giúp cho vi c sệ ắp xếp các ph n t l n nh t vầ ử ớ ấ ề cuối
- Về code, chúng ta sẽ chia ra làm 2 hàm, là hàm Heapify dùng để tạo ra kiểu dữ liệu Binary Max Heap và hàm thứ 2 là Heap Sort dùng để ắ s p xếp:
</div><span class="text_page_counter">Trang 7</span><div class="page_container" data-page="7">void Heapify( int a[], int n, int i){ int largest = i;
int left = 2*i+1;//xét v trí node bên trái ị int right=2*i+2;//xét v trí node bên ph i ị ả
//Nếu như cây con bên trái lớn hơn gốc thì ta sẽ cho gốc là node bên trái
if(left<n && a[left]>a[largest]) largest=left;
//Tương tự như cây con bên phải if(right<n && a[right]>a[largest])
largest=right;
//Nếu như phần tử lớn nhất khơng ph i là g c thì ta sả ố ẽ thay đổ ị trí của i v node đó với rễ sao cho phần tử lớn nhất ln là gốc
if(largest!=i)
Swap(a[i],a[largest]);
//Ta ti p tế ục đệ quy ti n trình trên v i các nodế ớ e ở hàng dưới cho đến khi ra một cây đệ quy lớn nhất hoàn chỉnh
Heapify(a,n,largest); }
void HeapSort(int a[], int n){
// cho i ch y tạ ừ giữa mảng để ạ t o thành m t cây nh phân ộ ị for(int i=n/2-1;i>=0;i--)
//Đổi ch giữa g c c a cây(thành phần lớn nh t) và vỗ ố ủ ấ ị trí cuối cùng của mảng, sau đó cho tạ ại cây mới sau khi cắo l t m t phần gốc để rút ấ gọn cây lại cho đến khi không cịn ph n tầ ử nào trong cây thì mảng đã
</div><span class="text_page_counter">Trang 8</span><div class="page_container" data-page="8">Về thời gian: vì độ dài c a mủ ột cây nh phân khi có n ph n t là log(n), ị ầ ử kể cả là trường h p x u nh t khi ta ph i di chuy n gợ ấ ấ ả ể ốc t i ph n node xa nhớ ầ ất thì v n là log(n). Và vì khi s p x p ta c n ph i duy t qua m ng n lẫ ắ ế ầ ả ệ ả ần nên độ phức t p lúc này sạ ẽ là O(n*log<small>2</small>(n))
Về không gian: O(1). 1.6. Thuật toán Merge Sort
- Ý tưởng: Thu t toán Merge Sort là thu t toán áp dậ ậ ụng phương pháp “Chia để trị” có độ phức tạp khi cài đặt ở mức trung bình và tốc độ khá nhanh trong các thuật toán s p x p. ắ ế Ở thuật tốn, ta sẽ chia mảng chính thành 2 mảng con, sau đấy ti p tế ục chia 2 mảng con thành 4 m ng con khác nhau,... ti p tả ế ục cho đến khi m ng ti p theo ả ế chỉ còn 1 ph n t thì ta s ầ ử ẽ so sánh và đổi chỗ phần t c a các m ng khác nhau. Cuử ủ ả ối cùng ta tr n các m ng l i theo quy tộ ả ạ ắc:
So sánh các ph n tầ ử đứng đầu, n u chúng nhế ỏ hơn thì cho vào danh sách mới, cho đến khi 1 trong 2 m ng là rả ỗng
Cuối cùng, khi 1 trong 2 mảng là r ng thì ta l y ph n còn l i c a mỗ ấ ầ ạ ủ ảng cho vào m ng mả ới, ta được một mảng mới đã đượ ắc s p x p. ế
- Về code, sẽ chia ra làm 2 hàm là hàm Merge và hàm MergeSort: void Merge(int a[], int const low, int const mid, ins const high){
//tạo ra 2 bi n h ng a1, a2(vì biế ằ ến động khi đặt làm độ ớ l n c a m ng ủ ả sẽ cho ra lỗi)
auto const a1=mid-low+1;//biến a1 lưu độ ớ l n c a mủ ảng đầu auto const a2=high-mid;//biến a2 lưu độ ớ l n c a m ng th hai ủ ả ứ auto * lowArray = new int[a1],//t o bi n con tr m ng lowArray vào ạ ế ỏ ả mảng có độ lớn a1
auto * highArray = new int[a2];//tương tư như trên với độ lớn a2 //chia các mảng ra để ắ s p x p theo 2 mế ảng
for (auto i = 0; i < a1; i++) lowArray[i] = a[low + i]; for (auto j = 0; j < a2; j++)
</div><span class="text_page_counter">Trang 9</span><div class="page_container" data-page="9">//sau khi đã hợp nhất xong, ta cần xóa các mảng tạm để giải phóng bộ nhớ vị các m ng t m là ki u dả ạ ể ữ liệu con trỏ để giải phóng b nh . ộ ớ
delete[] lowArray; delete[] highArray; }
void MergeSort(int a[], int const low, int const high){
if(low>=high) return;//điều kiện để thoát khỏi vòng lặp đệ quy auto mid=low+(high-low)/2;//lấy giá tr trung vị ị của mảng
</div><span class="text_page_counter">Trang 10</span><div class="page_container" data-page="10">//chạy đệ quy cho mảng nhằm t o ra 2 m ng và cu i cùng là h p nh t 2 ạ ả ố ợ ấ mảng đó lại và tiếp tục chạy đệ quy cho đến khi xảy ra điều kiện trên.
MergeSort(a, low, mid); MergeSort(a, mid + 1, high); Merge(a, low, mid, high); }
- Về độ ph c t p: ứ ạ
Thời gian: vì thu t tốn ln chia m ng ra làm 2 ph n tậ ả ầ ừng đôi một nên thu t tốn có thậ ể được tính dựa trên phương trình sau:
T(n)=2T(n/2)+θ(n)
có thể được tính là O(n*log<small>2</small>(n)) và ln có độ ph c tứ ạp như vậy trong mọi trường h p nên Merge Sort rợ ất được ưa chuộng b i vì tính ở ổn định về thời gian c a thuủ ật tốn.
Khơng gian:O(1).
1.7. Thuật tốn Quick Sort
- Về ý tưởng: thuật toán Quick Sort cũng sử dụng về ý tưởng “Chia để ị” tương tự tr như Merge Sort. Thế nhưng thay vì như Merge Sort chia các mảng ra thành 2 mảng khác nhau r i tiồ ếp tục chia 2 cho đến khi đơn giản thì Quick Sort sẽ chia mảng ra thành các mảng dựa trên phần tử thường được gọi là pivot(ph n tầ ử chốt). Thường ph n tầ ử chốt được chọn sẽ là ph n tầ ử trung vị(phần tử nằm ở giữa mảng), lúc này thu t tốn sậ ẽ có độ ph c t p nhứ ạ ỏ hơn so với khi ta ch n pivot nọ ằm ở ph n tầ ử đầu ho c cu ặ ối.
- Về code:
</div><span class="text_page_counter">Trang 11</span><div class="page_container" data-page="11">void QuickSort(int a[], int low, int high){
if(low>=high) return;//điều kiện để thoát khỏi đệ quy int l0=low;
int h0=high;
int pivot=a[low+(high-low)/2]//l y pivot nấ ằm ở giá trị trung vị c a mủ ảng while(l0<h0){
while(a[l0]<pivot) l0++;//tìm các giá trị được s p x p bên trái ắ ế ở while(a[h0]>pivot) h0--;//tương tự như ở bên phải
if(l0<h0){ //khi các giá trị chưa được sắp xếp ở 2 bên thì ta đổi ch ỗ
Thời gian: vì pivot của chúng ta khi cài đặt là trung vị c a mủ ảng, nên độ phức t p c a thu t toán luôn là ạ ủ ậ O(n*log<small>2</small>(n)), điều này khác v i vi c lớ ệ ấy pivot nằm ở giữa mảng vì lúc này khi ta chia m ng ra thì s có thả ẽ ể dính vào trường hợp pivot là giá trị l n nh t ho c nhớ ấ ặ ỏ nhất, độ phức tạp lúc này s là O(n ). Vì th nên pivot ẽ <small>2</small> ế thường được lấy ở ị v trí trung vị.
Khơng gian:O(1). 1.8. Thuật toán Radix Sort
- Ý tưởng: Thu t tốn Radix Sort hay cịn g i là Postmans Sort là m t trong nh ng ậ ọ ộ ữ thuật toán ph biổ ến dung để sắp xếp.Điểm khác bi t c a Radix Sort so v i các thu t toán ệ ủ ớ ậ sắp xếp khác chính là vi c thay vì so sánh các s vệ ố ới nhau để sắp xếp chúng theo các chiều tăng dần hoặc giảm d n, thì Radix Sort s d ng vi c phân chia các ch s thành t ng ch ầ ử ụ ệ ữ ố ừ ữ số khác nhau và chia chúng ra thành từng bucket theo hàng đơn vị, hàng chục, hàng trăm,… của chữ số và ti p tục như thế cho đếế n khi mảng đã đượ ắc s p x p. ế
- Về code:
</div><span class="text_page_counter">Trang 12</span><div class="page_container" data-page="12">//hàm GetMax dùng để lấy giá trị l n nh t c a mớ ấ ủ ảng int GetMax(int a[], int n){
//hàm CountSort dùng để sắp xếp các giá trị theo số chữ số được chia theo exp void CountSort(int a[], int const n, int exp) {
auto *output=new int [n];//mảng output được tr vào bỏ ộ nhớ có n vùng nh ớ int count[10] = {0};//mảng count dùng để đựng s ố chữ số c a mảng khi ủ được chia ra
for (int i = 0; i < n; i++) {
count[(a[i] / exp) % 10]++;//duy t mệ ảng để chia mảng theo số chữ số theo exp
}
for (int i = 1; i < 10; i++)
count[i] += count[i - 1];//thay đổi count i để mảng count ch a các sứ ố chữ ố theo đúng thứ s tự
for (int i = n - 1; i >= 0; i--) {
output[count[(a[i] / exp) % 10] - 1] = a[i];//t o mạ ảng output b ng cách s p x p các mằ ắ ế ảng theo sự xuất hiện c a sủ ố chữ số c a mảng a ủ
count[(a[i] / exp) % 10]--;//tiếp t c trụ ừ đi các khoảng c a mủ ảng count cho đến khi đã sắp xếp h t theo s các ch s . ế ố ữ ố
}
for (int i = 0; i < n; i++)
a[i] = output[i];//Copy mảng a theo mảng output để ảng a bây gi m ờ đã đượ ắc s p x p theo ế
</div><span class="text_page_counter">Trang 13</span><div class="page_container" data-page="13">Thời gian:Thu t toán Radix Sort ậ có độ ph c t p d trên s các ch s ứ ạ ữ ố ữ ố lớn nh t c a m ng O(d*(n+b)) v i d là sấ ủ ả ớ ố chữ số l n nhớ ất của mảng và b là độ lớn của mảng Count để chứa s các ch s . ố ữ ố
Khơng gian: vì cần thêm khơng gian để chứa các số chữ số nên độ phức tạp của thuật toán lúc này s là O(n+b). ẽ
</div><span class="text_page_counter">Trang 14</span><div class="page_container" data-page="14">- Ở độ lớn t 25000 tr lên, v i các thuừ ở ớ ật toán có độ phức tạp là O(n*log<small>2</small>(n)) có thời gian ch y không quá khác bi t so v i các thuạ ệ ớ ật tốn có độ ph c t p O(nứ ạ <small>2</small>). Đặc biệt là thuật toán Bubble Sort, thế nhưng thuật toán Shell Sort l i không quá bi t so v i các thuạ ệ ớ ật tốn có độ phức t p nhạ ỏ hơn.
- Thuật toán Radix Sort theo tính tốn là thu t tốn có tậ ốc độ nhanh nh t tuy nhiên ấ cũng không tạo ra nhiều s khác bi t so với các thu t toán Heap Sort, Quick Sort và Merge ự ệ ậ Sort.
Giải thích:
</div><span class="text_page_counter">Trang 15</span><div class="page_container" data-page="15">- Theo đánh giá về các thuật toán như ở trên, các thuật toán đều chạy tuân theo với độ ph c tứ ạp đã được tính tốn.
- Về sự khác biệt của Bubble Sort so v i Selection Sort và Insertion Sort chính là do ớ việc phải hốn đổi gi a các v trí trong mữ ị ảng c a Bubble Sort xủ ảy ra thường xuyên hơn so với 2 thu t toán trên nên c n nhiậ ầ ều thời gian hơn.
- Còn v Shell Sort tuy ề có độ ph c t p là O(n ) thứ ạ <small>2</small> ế nhưng độ phức tạp thực tế lại có thể nhỏ hơn do đặc thù của thuật tốn khiến cho thu t tốn có thậ ể có độ ph c t p nhứ ạ ỏ hơn nhờ vào độ chia.
2. Đối v i thuớ ật toán gần như đượ ắp xếp c s tăng dần
Hình 2: Th i gian các thu t tốn s p xờ ậ ắ ếp trong mảng gần như đượ ắc s p xếp tăng dần
Nhận xét:
- Các thu t toán O(n*log (n)) v n gi nguyên th i gian ch y c a mình v i m c x p ậ <small>2</small> ẫ ữ ờ ạ ủ ớ ứ ấ xỉ 0-200ms.
- Thuật toán ch y nhanh nh t là Insertion Sort v i tạ ấ ớ ốc độ ần như là 0ms. g - Thuật toán ch y ch m nh t v n là Bubble Sort. ạ ậ ấ ẫ
Giải thích:
</div>