基於比較的排序---選擇、插入、冒泡
初學排序時,也比較模糊,多是照貓畫虎,不能透徹理解。今天對幾種簡單的排序的做一小結。日後繼續學習、總結更多地、性能更優的排序!
一、選擇排序
先把代碼貼上
1 #include<stdio.h> 2 int main() 3 { 4 int a[9] = {5,7,4,6,1,9,3,2,8}; 5 int len = sizeof(a)/sizeof(int); 6 int i,j,min,temp,m; 7 for(i = 0; i < len; i++) 8 { 9 min = i; 10 for(j = i+1; j < len; j++) 11 { 12 if(a[min] > a[j]) 13 { 14 min = j; 15 } 16 } 17 18 if(min != i) 19 { 20 temp = a[min]; 21 a[min] = a[i]; 22 a[i] = temp; 23 } 24 }25 26 for(m = 0; m <len; m++) 27 { 28 printf("%d ",a[m]); 29 } 30 31 return 0; 32 33 }
此處以升序為例
如下圖所示,對該數組進行升序排序
選擇排序的原理其實很簡單,就是用一個變量min始終保存當前未排序序列的最小元素下標。當外層的第一次循環結束後,比較一下參加該次循環的下標是否和當前的min一致,如果一致,則不管,如果不一致交換兩個下標對應元素的位置。
下面針對這段話結合上圖做一分析:
第一趟:在比較之前,先定義min用來保存當前最小元素的下標。
a[min]分別和a[i+1](a[j])比較,第一次a[0](5)和a[1](7)比較,a[0]小,繼續,j++,接著a[0]和a[2]比較,a[0]大,則把當前j值的賦給min,即min = 2; 因為min保存的是當前最小元素下標,現在發現有人比他小了,就要更新自身的值了。那麽現在就是用a[2]和a[3]比較了,a[2]小,繼續j++。a[2]和a[4]比,a[4]小。更新min的值為4,j++。繼續用a[4]和a[5]比,a[4]小,j++。一直比較a[8],發現都是a[4]小,則第一趟比較結束。得出最小元素的下標為4。
然後用外層第一次進入循環的i值和min比較,如果不相等,說明這個i對應的元素不是最小元素,那麽就和min下標對應的元素互換位置,將最小元素置於數組首位了。
第二趟:此時的i等於2了,min也重新被初始為2,繼續讓a[min]和a[i+1]比較,步驟和第一趟的完全相同,這趟下來,又可以找到最小元素的角標。
接下來就是重復這個步驟了。
具體過程如下圖:
二、直接插入排序
先貼代碼
1 #include<stdio.h> 2 int main() 3 { 4 int a[5] = {5,7,4,6,3}; 5 int len = sizeof(a)/sizeof(int); 6 int i,j,temp,m; 7 for(i = 1; i < len; i++) 8 { 9 if(a[i] < a[i-1]) 10 { 11 temp = a[i]; 12 13 for(j = i-1; j >= 0 && a[j] > temp; j--) 14 { 15 a[j+1] = a[j]; 16 } 17 a[j+1] = temp; 18 } 19 } 20 for(m = 0; m < len; m++) 21 { 22 printf("%d ",a[m]); 23 } 24 return 0; 25 }
話都在圖裏了:
三、冒泡排序
貼代碼:
1 #include<stdio.h> 2 int main() 3 { 4 int a[5] = {5,6,3,7,4}; 5 int i,j,k,temp; 6 int len = sizeof(a)/sizeof(int); 7 8 for(i = 0; i < len - 1; i++) 9 { 10 bool flag = true; 11 for(j = 0; j < len - i - 1; j++) 12 { 13 if(a[j] > a[j+1]) 14 { 15 temp = a[j]; 16 a[j] = a[j+1]; 17 a[j+1] = temp; 18 flag = false; 19 } 20 21 } 22 if(flag) 23 { 24 break; 25 } 26 } 27 28 for(k = 0; k < len; k++) 29 { 30 printf("%d ",a[k]); 31 } 32 return 0; 33 }
上圖:
如圖所示,針對數組元素為5,6,3,7,4進行了冒泡排序,每次比較相鄰的兩個元素,若前者大於後者,則互換,反之,不換,繼續往後推進。但可以發現,在進行完三次冒泡之後,已經產生了最終結果:3,4,5,6,7。但程序並不會因此停止,它仍會繼續執行兩輪,進行最後兩次的冒泡,但這是沒有意義的。所以在代碼中增加了標誌flag的設定,如果沒有比較了,就不再執行操作,就可以認為,當前序已按照要求序列排列完畢!
總結:
簡單選擇排序:
基本思想為每一趟從待排序的數據元素中選擇最小(或最大)的一個元素作為數組首元素,直到所有元素排完為止,簡單選擇排序是不穩定排序。時間復雜度為O(n2)。
直接插入排序:
基本思想為每一步將一個待排序的記錄,插入到前面已經排好序的有序序列中,直到插完所有元素為止。時間復雜度為O(n2)。
冒泡排序:
基本思想為對相鄰的元素進行兩兩比較,順序相反則進行交換,這樣,每一趟會將最小或最大的元素“浮”到頂端,最終達到完全有序。時間復雜度依然為O(n2)
基於比較的排序---選擇、插入、冒泡