1. 程式人生 > >基於比較的排序---選擇、插入、冒泡

基於比較的排序---選擇、插入、冒泡

進入 因此 16px amp 一個 發現 i+1 所有 總結

初學排序時,也比較模糊,多是照貓畫虎,不能透徹理解。今天對幾種簡單的排序的做一小結。日後繼續學習、總結更多地、性能更優的排序!

一、選擇排序

先把代碼貼上

 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

基於比較的排序---選擇、插入、冒泡