排序算法學習整理二(選擇)
9二、選擇排序:
選擇排序十分的簡單和直觀,其的工作原理是每一次從待排序的數組中選出最小(或最大)的一個元素,存放在序列的起始位置。因此,選擇排序也是像我們這種萌新最容易寫出來的排序算法。
排序步驟:
- 選出最小的元素
- 放在數組最前面
- 選出第二小的元素
- 放在第二位
重復如此直到完成排序
下面舉個栗子:
有一個數組其元素如下 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 23 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交換一樣
所以為了防止出現這種情況就需要加上這塊代碼。
目前作為蒟蒻的我只能優化到這裏,如果有更好的優化,大家自行探索,我也會慢慢學習,繼續更新。
排序算法學習整理二(選擇)