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

排序算法學習整理二(選擇)

closed 元素 style clas 目前 i+1 spl 排序算法 出現

9二、選擇排序:

  選擇排序十分的簡單和直觀,其的工作原理是每一次從待排序的數組中選出最小(或最大)的一個元素,存放在序列的起始位置。因此,選擇排序也是像我們這種萌新最容易寫出來的排序算法。

  排序步驟:

  1. 選出最小的元素
  2. 放在數組最前面
  3. 選出第二小的元素
  4. 放在第二位

  重復如此直到完成排序

  下面舉個栗子:

    有一個數組其元素如下 5 1 4 3 2 6 7 0 9,其選擇排序流程如下

  

   第一輪:      0 1 4 3 2 6 9 5 7    0最小,0和5換
   第二輪:      0 1 4 3 2 6 9 5 7     1最小,不變
   第三輪:      0 1 2
3 4 6 9 5 7    2最小,2和4換
   第四輪:      0 1 2 3 4 6 9 5 7    3最小,不變
   第五輪:      0 1 2 3 4 5 9 6 7    5最小,5和6換
   第六輪:      0 1 2 3 4 5 6 9 7    6最小,6和9換
   第七輪:      0 1 2 3 4 5 6 9 7    7最小,7和9換
   
第八輪:      0 1 2 3 4 5 6 9 7    已經完成排序,但任然需要比較

  從這個栗子,我們可以得出選擇排序的核心代碼:

  if (arr[min] > arr [j])
  {
      min = j;
  }
  arr[min] = arr[min] ^ arr[i];
  arr[i] = arr[min] ^ arr[i];
  arr[min] = arr[min] ^ arr[i];

  接著我們繼續思考,兩層for循環,首先是第一層,第一層循環有兩個作用,第一個:從0~n-1一個個進行排序;二:表示需要比較的次數。由第一個作用我們可以知道第一層for循環的循環變量i<=n-1,由第二個作用可知i<n-1。(十個數比較只需要比較9次,且c的數組從0開始所以到9就是第十個元素,所以第九次比較就是當i=8的時候)由此可以得出第一層for的代碼為 for (int i = 0; i < n-1; i++)。註:我們也可以從i = 1開始,略微改動一下循環終止條件就可以了。

  然後我們來確定一下第二層for循環,第二層for循環的作用很簡單就是讓當前元素與無序的元素進行比較,這裏的難點在於無序的元素和當前元素的確定,讓我們來回憶一下,第一層for循環的i是從0開始的那麽我們的第二層for循環為了避免重復比較,所以第二層for循環的循環變量j應該從i+1開始,到哪裏裏終止呢?因為每一次都是把最下的元素放到最前面所以從 i 到 n-1都是無序元素,所以當j < n 時,進行循環。由此推出第二層循環 for (int j = i+1; j < n; j++)。如果一層for循環從1開始的,自行調整一下即可。

  至此我們就能寫出完整的選擇排序代碼了。嗯?不對,還有個問題,我們的min該等於什麽,嗯,沒錯,min = i,就可以了。

  好了現在我們開始寫最後的代碼吧

技術分享圖片
 1 void sort(int *arr, int count)
 2 {
 3     for (int i = 0; i < count-1; i++)
 4     {
 5         int min = i;    
 6         for (int j = i+1; j < count; j++)
 7         {
 8             if (arr[min] > arr[j])
 9             {
10                 min = j;   //找到比arr[min]小的先不交換,先保留下標
11             }
12         }
13         if (min != i)   //為了避免arr[i],本身就是最小值任然進行交換的情況 。
14         {
15             arr[min] = arr[min] ^ arr[i];
16             arr[i] = arr[min] ^ arr[i];
17             arr[min] = arr[min] ^ arr[i];
18         }
19     }
20 }
View Code

  現在我們來想一想如何優化一下選擇排序,其實很明顯了,在交換方面我們已經沒有辦法優化了(至少對我這個蒟蒻來說)。那麽我們來思考一下,選擇排序每次選出最小的放在最前面,或者選出最大的放在最前。我們不僅可以選出最小的也可以選出最大,所以我們就在選出最小值的同時選出最大值,比較所消耗的時間要比循環少,略有優化。

  按照這個思想可以寫出代碼如下:

技術分享圖片
 1 void sort(int *arr, int count)
 2 {
 3     int left = 0;
 4     int right = count-1;
 5     int min = left;
 6     int max = right;
 7 
 8     while (left < right)
 9     {
10         min = left;
11         max = left;
12         for (int i = left; i <= right; i++)
13         {
14             if (arr[min] > arr[i])
15             {
16                 min = i;
17             }
18             if (arr[max] < arr[i])
19             {
20                 max = i;
21             }
22         }
23 
24         if (left != min)    //最小交換
25         {
26             arr[min] = arr[min] ^ arr[left];
27             arr[left] = arr[min] ^ arr[left];
28         }
29 
30         if (max == left)    //防止當min最小,max最大時產生連續交換
31         {
32             max = min;
33         }
34 
35         if (right != max)   //最大交換
36         {
37             arr[max] = arr[max] ^ arr[right];
38             arr[right] = arr[max] ^ arr[right];
39             arr[max] = arr[max] ^ arr[right];
40         }
41         left++;
42         right--;
43     }
44 }
View Code

  這裏要特別說明一下這段代碼

        if (max == left)   
        {
            max = min;
        }

  為什麽一定要寫這段代碼呢,

  我們 來看個例子 :

    有個數組其元素為 9 1 5 6 0;

      max = 0,min = 4;

    執行min交換後,0 1 5 6 9;

      max = 0,min = 4;

    這時候如果執行max循環那麽,數組就和沒有執行min交換一樣

所以為了防止出現這種情況就需要加上這塊代碼。

  目前作為蒟蒻的我只能優化到這裏,如果有更好的優化,大家自行探索,我也會慢慢學習,繼續更新。

排序算法學習整理二(選擇)