1. 程式人生 > >資料結構---九大排序演算法再總結

資料結構---九大排序演算法再總結

排序:對一序列物件根據某個關鍵字進行排序;

穩定:如果a原本在b前面,而a=b,排序之後a仍然在b的前面;

不穩定:如果a原本在b的前面,而a=b,排序之後a可能會出現在b的後面;

內排序:所有排序操作都在記憶體中完成;

外排序:由於資料太大,因此把資料放在磁碟中,而排序通過磁碟和記憶體的資料傳輸才能進行;

排序耗時的操作:比較、移動;

排序分類:

(1)交換類:氣泡排序、快速排序;此類的特點是通過不斷的比較和交換進行排序;

(2)插入類:簡單插入排序、希爾排序;此類的特點是通過插入的手段進行排序;

(3)選擇類:簡單選擇排序、堆排序;此類的特點是看準了再移動;

(4)歸併類:歸併排序;此類的特點是先分割後合併;

歷史程序:一開始排序演算法的複雜度都在O(n^2),希爾排序的出現打破了這個僵局;

以下視訊是Sapientia University創作的,用跳舞的形式演示排序步驟,這些視訊就可以當作複習排序的資料~

上面介紹的排序演算法都是基於排序的,還有一類演算法不是基於比較的排序演算法,即計數排序、基數排序

預備:最簡單的排序

此種實現方法是最簡單的排序實現;

缺點是每次找最小值都是單純的找,而沒有為下一次尋找做出鋪墊;

演算法如下:

  1. public
    staticint[] simple_sort(int[] arr) {  
  2.     for (int i = 0; i < arr.length; i++) {  
  3.         for (int j = i + 1; j < arr.length; j++) {  
  4.             if (arr[i] > arr[j]) {  
  5.                 swap(arr, i, j);  
  6.             }  
  7.         }  
  8.     }  
  9.     return arr;  
  10. }  

一、氣泡排序

氣泡排序相對於最簡單的排序有了改進,即每次交換都是對後續有幫助的,大數將會越來越大,小的數將會越來越小;

氣泡排序思想:兩兩相鄰元素之間的比較,如果前者大於後者,則交換

因此此排序屬於交換排序一類,同類的還有現在最常用的排序方法:快速排序;

1.標準氣泡排序

此種方法是最一般的氣泡排序實現,思想就是兩兩相鄰比較並交換;

演算法實現如下:

  1. publicstaticint[] bubble_sort2(int[] arr) {  
  2.     for (int i = 0; i < arr.length; i++) {  
  3.         for (int j = arr.length - 1; j > i; j--) {  
  4.             if (arr[j] < arr[j - 1]) {  
  5.                 swap(arr, j, j - 1);  
  6.             }  
  7.         }  
  8.     }  
  9.     return arr;  
  10. }  

2.改進氣泡排序

改進在於如果出現一個序列,此序列基本是排好序的,如果是標準的氣泡排序,則還是需要進行不斷的比較;

改進方法:通過一個boolean isChanged,如果一次迴圈中沒有交換過元素,則說明已經排好序;

演算法實現如下:

  1. // 最好:n-1次比較,不移動,因此時間複雜度為O(n),不佔用輔助空間
  2. // 最壞:n(n-1)/2次比較和移動,因此O(n^2),佔用交換的臨時空間,大小為1;
  3. publicstaticint[] bubble_sort3(int[] arr) {  
  4.     boolean isChanged = true;  
  5.     for (int i = 0; i < arr.length && isChanged; i++) {  
  6.         isChanged = false;  
  7.         for (int j = i + 1; j < arr.length; j++) {  
  8.             if (arr[i] > arr[j]) {  
  9.                 swap(arr, i, j);  
  10.                 isChanged = true;  
  11.             }  
  12.         }  
  13.     }  
  14.     return arr;  
  15. }  

二、簡單選擇排序

簡單選擇排序特點:每次迴圈找到最小值,並交換,因此交換次數始終為n-1次;

相對於最簡單的排序,對於很多不必要的交換做了改進,每個迴圈不斷比較後記錄最小值,只做了一次交換(當然也可能不交換,當最小值已經在正確位置)

演算法如下:

  1. //最差:n(n-1)/2次比較,n-1次交換,因此時間複雜度為O(n^2)
  2. //最好:n(n-1)/2次比較,不交換,因此時間複雜度為O(n^2)
  3. //好於氣泡排序
  4. publicstaticint[] selection_sort(int[] arr) {  
  5.     for (int i = 0; i < arr.length - 1; i++) {  
  6.         int min = i;  
  7.         for (int j = i + 1; j < arr.length; j++) {  
  8.             if (arr[min] > arr[j]) {  
  9.                 min = j;  
  10.             }  
  11.         }  
  12.         if (min != i)  
  13.             swap(arr, min, i);  
  14.     }  
  15.     return arr;  
  16. }  

三、簡單插入排序

思想: 給定序列,存在一個分界線,分界線的左邊被認為是有序的,分界線的右邊還沒被排序,每次取沒被排序的最左邊一個和已排序的做比較,並插入到正確位置;我們預設索引0的子陣列有序;每次迴圈將分界線右邊的一個元素插入有序陣列中,並將分界線向右移一位;

演算法如下:

  1. // 最好:n-1次比較,0次移動 ,時間複雜度為O(n)
  2. // 最差:(n+2)(n-1)/2次比較,(n+4)(n-1)/2次移動,時間複雜度為 O(n^2)
  3. publicstaticint[] insertion_sort(int[] arr) {  
  4.     int j;  
  5.     for (int i = 1; i < arr.length; i++) {  
  6.         if (arr[i] < arr[i - 1]) {  
  7.             int tmp = arr[i];  
  8.             for (j = i - 1; j >= 0 && arr[j] > tmp; j--) {  
  9.                 arr[j + 1] = arr[j];  
  10.             }  
  11.             arr[j + 1] = tmp;  
  12.         }  
  13.     }  
  14.     return arr;  
  15. }  

簡單插入排序比選擇排序和氣泡排序好!


四、希爾排序

1959年Shell發明;

第一個突破O(n^2)的排序演算法;是簡單插入排序的改進版;

思想:由於簡單插入排序對於記錄較少或基本有序時很有效,因此我們可以通過將序列進行分組排序使得每組容量變小,再進行分組排序,然後進行一次簡單插入排序即可;

這裡的分組是跳躍分組,即第1,4,7位置為一組,第2,5,8位置為一組,第3,6,9位置為一組;

索引

1

2

3

4

5

6

7

8

9

此時,如果increment=3,則i%3相等的索引為一組,比如索引1,1+3,1+3*2

一般增量公式為:increment = increment/3+1;

演算法實現如下:

  1. // O(n^(3/2))
  2. //不穩定排序演算法
  3. publicstaticint[] shell_sort(int[] arr) {  
  4.     int j;  
  5.     int increment = arr.length;  
  6.     do {  
  7.         increment = increment / 3 + 1;  
  8.         for (int i = increment; i < arr.length; i++) { //i=increment 因為插入排序預設每組的第一個記錄都是已排序的
  9.             if (arr[i] < arr[i - increment]) {  
  10.                 int tmp = arr[i];  
  11.                 for (j = i - increment; j >= 0