1. 程式人生 > >排序算法(學習整理)

排序算法(學習整理)

下標 borde sort strong splay 簡單 記錄 簡單的 tro

  排序的算法有很多,冒泡、選擇、直接插入、雞尾酒、快排、堆排......,下文主將盡可能的介紹本人學過的所有排序(會不斷更新,本人還在學習),以從小到大為最終排序結果,C 為主要實現語言。

一、冒泡排序(Bubble Sort):

  冒泡排序是一種簡單的利用交換來完成排序的算法。它重復地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重復地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端。

  冒泡算法的步驟

  • 比較相鄰的元素。如果前一個元素數比後一個元素大,就交換它們兩個。
  • 對每一對相鄰元素做同樣的工作,從開始0和1到結尾的n-1和n。所以,最後的元素應該會是最大的數。
  • 針對所有的元素重復以上的步驟,除了最後一個。
  • 持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。

  下面是代碼

技術分享圖片
 1 void bubble_sort(int arr[], int len)
 2 {
 3     int i, j;  
 4     for (i = 0; i < len - 1; i++)                  //需要進行比較的輪數
 5     {    
 6         for (j = 0; j < len - 1 - i; j++)          //每輪需要進行比較的次數,
 7        //因為每一輪都有一個最大的數被放到了最後一個,所以第i輪就有i個數不需要排序(這裏就存在優化的可能)
8 if (arr[j] > arr[j + 1]) //相鄰的兩個元素兩兩進行比較 9 { 10 arr[j] = arr[j] ^ arr[j+1]; 11 arr[j+1] = arr[j] ^ arr[j+1]; 12 arr[j] = arr[j] ^ arr[j+1]; // 交換 13 } 14 } 15 }
Bubble sort

冒泡排序的問題很明顯,舉個例子

當數組元素為 1 2 3 9 4 5 6 7 8 時:

  第一輪:1 2 3 4 5 6 7 8 9;

  第二輪:1 2 3 4 5 6 7 8 9;

  第三輪:1 2 3 4 5 6 7 8 9;

至此我們可以看出在第一輪的時候數組就已經排好序了,然而冒泡排序仍然在兢兢業業的工作(真是好員工,可惜效率低了點)。

所以我們可嘗試著優化一下,在進行交換的時候標記一下,當發數組遍歷完都沒有交換的情況,也就證明已經排好序了,我們的冒泡排序就可以提前下班了。

  優化後的代碼如下

技術分享圖片
 1 void bubble_sort(int arr[], int len)
 2 {
 3     int i, j; 
 4     for (i = 0; i < len - 1; i++)                  //需要進行比較的輪數
 5     {    
 6         int isSorted = 1;                          //用isSorted進行標記,默認其為已經完成排序,也可以設置為bool型
 7         for (j = 0; j < len - 1 - i; j++)          //每輪需要進行比較的次數
 8         {
 9             //因為每一輪都有一個最大的數被放到了最後一個,所以第i輪就有i個數不需要排序
10             if (arr[j] > arr[j + 1])                   //相鄰的兩個元素兩兩進行比較
11             {
12                 isSorted = 0;                     //進入交換後立刻置0, 表示排序未完成
13                 arr[j] = arr[j] ^ arr[j+1];                 
14                 arr[j+1] = arr[j] ^ arr[j+1];
15                 arr[j] = arr[j] ^ arr[j+1];            //交換
16             }
17         }
18         if (isSorted)                   //如果一直未交換就代表已經完成了排序,也就是說可以提前下班了
19         {
20             break;
21         }
22     }
23 }
View Code

當我們繼續測試後會發現冒泡排序的另一個問題

打個比方:

  當數組為 33 54 32 21 56 67 78 89 時:

  第二個for裏

     第一輪比較次數:7

     第二輪比較次數:7

     第三輪比較次數:7

     第四輪比較次數:7

  程序結束

  第一輪的7次是怎麽來的呢?

    33和54比較,33 < 54,所以不變。    

    54和32比較,54 > 32,所以54和32換。 

       33 32 54 21 56 67 78 89

    54和21比較,54 > 21,所以54和21換。 

       33 32 21 54 56 67 78 89

    54和56比較,54 < 56, 不變。

    56和67比較,56 < 67,不變。

    67和78比較, 67 < 78,不變。

    78和89比較, 78 < 89, 不變。

  第一輪至此結束。

  第二輪的6次

    33和32比較, 33 > 32, 所以33和32交換。

       32 33 21 54 56 67 78 89

    33和21比較, 33 > 21,所以33和21交換。

       32 21 33 54 56 67 78 89

    33和54比較,33 < 54,所以不變。

    54和56比較,54 < 56, 不變。

    56和67比較,56 < 67,不變。

    67和78比較, 67 < 78,不變。

  第二輪至此結束。

到這裏基本就能看出問題了,這個測試組,從56往後都是有序的,但是冒泡這位員工仍然一絲不茍的執行的他的任務。

從56往後的比較都是沒有意義的,所以我們應該考慮如何讓程序識別已排好序的子列。大家可以思考一下然後再往後看。

解決方法:我們只需將要再最後一次元素進行交換的位置進行記錄,讓第二for循環再這個範圍內進行比較。

    

  最終優化代碼如下(對我來說):

技術分享圖片
 1 void bubble_sort(int arr[], int len)
 2 {
 3     int i, j;
 4     int lastIndex, sortBorder;                      //用來記錄最後一次交換的下標和交換邊界
 5     sortBorder = len -1;                            //因為第一輪的時候i = 0,所以第一輪的sortBorder == len - i - 1
 6     for (i = 0; i < len - 1; i++)                  //需要進行比較的輪數
 7     {    
 8         int isSorted = 1;                          //用isSorted進行標記,默認其為已經完成排序,也可以設置為bool型
 9         for (j = 0; j < sortBorder; j++)          //每輪需要進行比較的次數
10         {
11             //這裏不在由i確定循環邊界了,這也是這次優化的核心
12             if (arr[j] > arr[j + 1])                   //相鄰的兩個元素兩兩進行比較
13             {
14                 isSorted = 0;                     //進入交換後立刻置0, 表示排序未完成
15                 lastIndex = j;                         //記錄下最後一次交換的位置
16                 arr[j] = arr[j] ^ arr[j+1];                 
17                 arr[j+1] = arr[j] ^ arr[j+1];
18                 arr[j] = arr[j] ^ arr[j+1];            //交換
19             }
20         }
21         sortBorder = lastIndex;               //講最後一次交換的位置作為下次比較的邊界
22         if (isSorted)                   //如果一直未交換就代表已經完成了排序,也就是說可以提前下班了
23         {
24             break;
25         }
26     }
27 }
View Code

當然這也不最優的冒泡優化,但是繼續優化就涉及到另一個算法了,所以目前對冒泡這個員工的整改就到這裏


  

排序算法(學習整理)