資料結構第八章學習小結
一、學習內容小結
排序可分為兩大類:
內部排序(Internal Sorting):待排序的記錄全部存放在計算機記憶體中進行的排序過程;
外部排序(External Sorting):待排序的記錄數量很大,記憶體不能儲存全部記錄,需要對外存進行訪問的排序過程。(現階段還沒有詳細深入的學習)
(本章學習的排序方法比較多,有點容易混淆,難記憶,花了比較多的時間在把各類方法總結成表格,看著對比比較清晰易懂一些。)
排序方法分類 |
排序方法 (內部排序) |
概述 |
時間複雜度分析 |
空間複雜度分析 |
演算法特點 (優缺點) |
|
交換類 |
氣泡排序 |
重複走訪過要排序的元素列,依次比較兩個相鄰的元素,如果順序錯誤就把他們交換過來 |
O(n^2) |
O(1) (兩元素交換時,只需要一個記錄的輔助空間) |
優點:①穩定排序②可用於鏈式儲存結構 缺點:①不適用於初始記錄無序、n較大的情況 |
|
|
快速排序 |
通過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。 |
O(nlog(2)(n)) |
最好情況: O(log(2)(n)) 最壞情況:O(n) (遞迴,執行時需要一個棧存放資料,最大遞迴呼叫次數與遞迴樹深度一致) |
優點:①適用於初始記錄無序、n較大的情況(是所有內部排序中最快的方法) 缺點:①只能用於順序儲存結構②不穩定排序 |
|
插入類 |
直接插入排序 |
(順序查詢)將一條記錄插入到已排好序的有序表中得到一個新的、記錄數量增加1的有序表。 |
最好情況:比較1次,不移動 最壞情況:(非遞增有序列)比較i次,移動i+1次 |
平均:O(n^2) |
O(1) (只需要一個記錄的輔助空間r[0]) |
優點:①穩定排序②演算法簡便③可用於鏈式儲存結構④適用於初始記錄基本有序(正序) 缺點:①當初始記錄基本無序、n較大時複雜度高,不適用 |
|
折半插入排序 |
對直接插入排序演算法的改進,排序原理同直接插入演算法。(在插入到已排序的資料時採用來折半查詢(二分查詢) |
O(n^2) (與直接插入排序相比,減少了比較次數,移動次數不變) |
O(1) (只需要一個記錄的輔助空間r[0]) |
優點:①穩定排序②適用於初始記錄無序、n較大的情況 缺點:①只能用於順序儲存結構 |
|
|
希爾排序 (縮小增 量排序) |
(分組插入) 把記錄按下標的一定增量分組,對每組使用直接插入排序演算法排序;隨著增量逐漸減少,每組包含的關鍵詞越來越多,當增量減至1時,演算法便終止。 |
O(nlog(2)(n))~O(n^2) (不確定) |
O(1) (只需要一個記錄的輔助空間r[0]) |
(要使增量序列中的值沒有除1之外的公因子,並且在最後增量值必須等於1) 優點:①適用於初始記錄無序、n較大的情況 缺點:①只能用於順序儲存結構②不穩定排序 |
|
選擇類 |
簡單選擇排序 |
先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。以此類推,直到所有元素均排序完畢。 |
O(n) |
O(1) (兩元素交換時,只需要一個記錄的輔助空間) |
①穩定排序(但可能產生“不穩定現象”)②可用於鏈式儲存結構③移動記錄次數少,當每一記錄佔用空間較多時,該法比直接插入排序快
|
|
|
樹形選擇排序 |
首先對n個記錄的關鍵字進行兩兩比較,然後在n/2個較小者之間再進行兩兩比較,如此重複,直至選出最小的記錄為止。 |
O(nlog(2)(n)) |
|
缺點:①輔助儲存空間較多②和“最大值”進行多餘比較等缺點 |
|
|
堆排序 |
是一種樹形選擇排序,將待排序的記錄r[1,n]看作一棵完全二叉樹的順序儲存結構,利用其中雙親結點和孩子結點之間的內在關係,在當前的無序序列中選擇最大(小)記錄。 |
O(nlog(2)(n)) |
O(1) (兩元素交換時,只需要一個記錄的輔助空間) |
優點:①適用於初始記錄無序、n較大的情況,記錄較少時不適用 缺點:①只能用於順序儲存結構②不穩定排序 |
|
歸併類 |
2-路歸併排序 |
遞迴算法:反覆將當前區間[left, right]分為兩半,對兩個子區間[left, mid]與[mid +1, right]分別遞迴進行歸併排序,然後將兩個已經有序的合併為有序序列。 |
O(nlog(2)(n)) 需要進行log(2)(n)(向上取整)躺歸併排序,每一趟O(n)
|
O(n) (需要和待排序記錄個數相等的輔助儲存空間) |
優點:①穩定排序②可用於鏈式儲存結構,且不需要附加儲存空間,但遞迴實現時仍要開闢相應的遞迴工作棧 |
至於更詳細的描述推薦參考這個網站的資料:https://www.cnblogs.com/hokky/p/8529042.html
(裡面對每一種方法都進行了非常詳細的描述,還有演算法思路的動圖jpg演示,非常清晰,簡潔易懂)
二、程式碼實戰
一開始做PTA上的作業題的時候還沒有想到原來方法挺簡單的,以為是要考察課本上的幾個演算法,然後用幾個排序方法試了挺久的。後來在網上查閱了一下才發現原來可以這麼簡單的完成=。=,還了解並學習到了桶排序這個排序方法的簡單思路。
因為每個員工的工齡在[0,50]這個區間上,所以可以開個小陣列作為桶。
1 #include <iostream> 2 using namespace std; 3 4 int main() 5 { 6 int n,x; 7 cin >> n; 8 int count[51] = { 0 }; 9 for (int i = 0; i < n; i++) 10 { 11 cin >> x; 12 count[x]++; 13 } 14 for (int i = 0; i < 51; i++) 15 if (count[i]) 16 cout << i << ":" << count[i] << endl; 17 return 0; 18 }View Code
還有實踐1PTA排名彙總的演算法思路,總體看起來不是很困難,用了<algorithm>標頭檔案中的sort函式就比較簡便,基本就是將考生在考場內及總體分別排名一次(記得考慮同分的情況),再將總體的資料輸出。(在程式碼中也作了比較清晰的註釋,應該會比較易懂)
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 using namespace std; 5 6 struct student 7 { 8 string id; //考號 9 int score; //分數 10 int position; //考點 11 int rank; // 所在考點排名 12 int total_rank; //總排名 13 }stu[30010]; 14 15 int compare(student a, student b) 16 { 17 if(a.score==b.score) 18 { 19 return a.id<b.id; 20 } 21 return a.score>b.score; 22 } 23 24 int main() 25 { 26 int N, K; 27 int num=0; 28 cin >> N; 29 30 for(int i=0;i<N;i++) 31 { 32 cin >> K; 33 for(int j=num;j<num+K;j++) 34 { 35 cin >> stu[j].id >> stu[j].score; 36 stu[j].position = i+1; 37 } 38 sort(stu+num,stu+num+K,compare); //同一考場排序 39 40 int rank = 1; 41 stu[num].rank = rank; //組中第一人排名為1 42 43 for(int t=num+1;t<K+num;t++) //確定組中排名 44 { 45 rank++; 46 if(stu[t].score==stu[t-1].score) //同分並列 47 { 48 stu[t].rank = stu[t-1].rank; 49 } 50 else 51 { 52 stu[t].rank = rank; //排名+1 53 } 54 } 55 num = num+K; //更新stu長度 56 } 57 58 sort(stu,stu+num,compare);//全部考生排序 59 60 int rank=1; 61 stu[0].total_rank = rank; 62 for(int i=1;i<num;i++) 63 { 64 rank++; 65 if(stu[i].score ==stu[i-1].score) 66 { 67 stu[i].total_rank = stu[i-1].total_rank; 68 } 69 else 70 { 71 stu[i].total_rank = rank; 72 } 73 } 74 75 cout << num << endl; 76 77 for(int i=0;i<num;i++) 78 { 79 cout << stu[i].id << " " << stu[i].total_rank << " " << stu[i].position << " " << stu[i].rank << endl; 80 } 81 82 return 0; 83 }View Code
三、學習心得
本學期的內容已經到此結束了,我覺得讓我感觸很深的反而是每一次的寫部落格,每進行一章節的部落格總結,都可以從頭把內容溫習一遍,這個感覺十分好,同時也可以相互學習。本章的各種排序方法是演算法思路不算特別困難,但是打起程式碼來還是有點吃力,還有比較多的知識點要記牢、區分,希望自己在接下來的複習階段多看看程式碼,掌握思路的同時也要強化臨時打程式碼的能力。