數據結構與算法--冒泡、選擇、插入算法

Java數據結構和算法(三)——冒泡、選擇、插入排序算法

 

 


  上一篇博客咱們實現的數組結構是無序的,也就是純粹按照插入順序進行排列,那麼如何進行元素排序,本篇博客咱們介紹幾種簡單的排序算法。java

一、冒泡排序

  這個名詞的由來很好理解,通常河水中的冒泡,水底剛冒出來的時候是比較小的,隨着慢慢向水面浮起會逐漸增大,這物理規律我不做過多解釋,你們只須要了解便可。算法

  冒泡算法的運做規律以下:數組

  ①、比較相鄰的元素。若是第一個比第二個大,就交換他們兩個。數據結構

  ②、對每一對相鄰元素做一樣的工做,從開始第一對到結尾的最後一對。這步作完後,最後的元素會是最大的數(也就是第一波冒泡完成)。數據結構和算法

  ③、針對全部的元素重複以上的步驟,除了最後一個。post

  ④、持續每次對愈來愈少的元素重複上面的步驟,直到沒有任何一對數字須要比較。性能

  

 

  

  代碼以下:url

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package  com.ys.sort;
 
public  class  BubbleSort {
     public  static  int [] sort( int [] array){
         //這裏for循環表示總共須要比較多少輪
         for ( int  i =  1  ; i < array.length; i++){
             //設定一個標記,若爲true,則表示這次循環沒有進行交換,也就是待排序列已經有序,排序已經完成。
             boolean  flag =  true ;
             //這裏for循環表示每輪比較參與的元素下標
             //對當前無序區間array[0......length-i]進行排序
             //j的範圍很關鍵,這個範圍是在逐步縮小的,由於每輪比較都會將最大的放在右邊
             for ( int  j =  0  ; j < array.length-i ; j++){
                 if (array[j]>array[j+ 1 ]){
                     int  temp = array[j];
                     array[j] = array[j+ 1 ];
                     array[j+ 1 ] = temp;
                     flag =  false ;
                 }
             }
             if (flag){
                 break ;
             }
             //第 i輪排序的結果爲
             System.out.print( "第" +i+ "輪排序後的結果爲:" );
             display(array);
             
         }
         return  array;
         
     }
     
     //遍歷顯示數組
     public  static  void  display( int [] array){
         for ( int  i =  0  ; i < array.length ; i++){
             System.out.print(array[i]+ " " );
         }
         System.out.println();
     }
     
     public  static  void  main(String[] args) {
         int [] array = { 4 , 2 , 8 , 9 , 5 , 7 , 6 , 1 , 3 };
         //未排序數組順序爲
         System.out.println( "未排序數組順序爲:" );
         display(array);
         System.out.println( "-----------------------" );
         array = sort(array);
         System.out.println( "-----------------------" );
         System.out.println( "通過冒泡排序後的數組順序爲:" );
         display(array);
     }
 
}

  

  結果以下:spa

  

  原本應該是 8 輪排序的,這裏咱們只進行了 7 輪排序,由於第 7 輪排序以後已是有序數組了。

  冒泡排序解釋:

  冒泡排序是由兩個for循環構成,第一個for循環的變量 i 表示總共須要多少輪比較,第二個for循環的變量 j 表示每輪參與比較的元素下標【0,1,......,length-i】,由於每輪比較都會出現一個最大值放在最右邊,因此每輪比較後的元素個數都會少一個,這也是爲何 j 的範圍是逐漸減少的。相信你們理解以後快速寫出一個冒泡排序並不難。

  冒泡排序性能分析:

  假設參與比較的數組元素個數爲 N,則第一輪排序有 N-1 次比較,第二輪有 N-2 次,如此類推,這種序列的求和公式爲:

  (N-1)+(N-2)+...+1 = N*(N-1)/2

  當 N 的值很大時,算法比較次數約爲 N2/2次比較,忽略減1。

  假設數據是隨機的,那麼每次比較可能要交換位置,可能不會交換,假設機率爲50%,那麼交換次數爲 N2/4。不過若是是最壞的狀況,初始數據是逆序的,那麼每次比較都要交換位置。

  交換和比較次數都和N2 成正比。因爲常數不算大 O 表示法中,忽略 2 和 4,那麼冒泡排序運行都須要 O(N2) 時間級別。

  其實不管什麼時候,只要看見一個循環嵌套在另外一個循環中,咱們均可以懷疑這個算法的運行時間爲 O(N2)級,外層循環執行 N 次,內層循環對每一次外層循環都執行N次(或者幾分之N次)。這就意味着大約須要執行N2次某個基本操做。

  

二、選擇排序 

  選擇排序是每一次從待排序的數據元素中選出最小的一個元素,存放在序列的起始位置,直到所有待排序的數據元素排完。

  分爲三步:

  ①、從待排序序列中,找到關鍵字最小的元素

  ②、若是最小元素不是待排序序列的第一個元素,將其和第一個元素互換

  ③、從餘下的 N - 1 個元素中,找出關鍵字最小的元素,重複(1)、(2)步,直到排序結束

   

  

 

   代碼以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package  com.ys.sort;
 
public  class  ChoiceSort {
     public  static  int [] sort( int [] array){
         //總共要通過N-1輪比較
         for ( int  i =  0  ; i < array.length- 1  ; i++){
             int  min = i;
             //每輪須要比較的次數
             for ( int  j = i+ 1  ; j < array.length ; j++){
                 if (array[j]<array[min]){
                     min = j; //記錄目前能找到的最小值元素的下標
                 }
             }
             //將找到的最小值和i位置所在的值進行交換
             if (i != min){
                 int  temp = array[i];
                 array[i] = array[min];
                 array[min] = temp;
             }
             //第 i輪排序的結果爲
             System.out.print( "第" +(i+ 1 )+ "輪排序後的結果爲:" );
             display(array);
         }
         return  array;
     }
 
     //遍歷顯示數組
     public  static  void  display( int [] array){
         for ( int  i =  0  ; i < array.length ; i++){
             System.out.print(array[i]+ " " );
         }
         System.out.println();
     }
     
     public  static  void  main(String[] args){
         int [] array = { 4 , 2 , 8 , 9 , 5 , 7 , 6 , 1 , 3 };
         //未排序數組順序爲
         System.out.println( "未排序數組順序爲:" );
         display(array);
         System.out.println( "-----------------------" );
         array = sort(array);
         System.out.println( "-----------------------" );
         System.out.println( "通過選擇排序後的數組順序爲:" );
         display(array);
     }
}

  運行結果:

  

 

  選擇排序性能分析:

  選擇排序和冒泡排序執行了相同次數的比較:N*(N-1)/2,可是至多隻進行了N次交換。

  當 N 值很大時,比較次數是主要的,因此和冒泡排序同樣,用大O表示是O(N2) 時間級別。可是因爲選擇排序交換的次數少,因此選擇排序無疑是比冒泡排序快的。當 N 值較小時,若是交換時間比選擇時間大的多,那麼選擇排序是至關快的。

  

三、插入排序

  直接插入排序基本思想是每一步將一個待排序的記錄,插入到前面已經排好序的有序序列中去,直到插完全部元素爲止。

  插入排序還分爲直接插入排序、二分插入排序、鏈表插入排序、希爾排序等等,這裏咱們只是以直接插入排序講解,後面講高級排序的時候會將其餘的。

    

 

  

 

  代碼以下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package  com.ys.sort;
 
public  class  InsertSort {
     public  static  int [] sort( int [] array){
         int  j;
         //從下標爲1的元素開始選擇合適的位置插入,由於下標爲0的只有一個元素,默認是有序的
         for ( int  i =  1  ; i < array.length ; i++){
             int  tmp = array[i]; //記錄要插入的數據
             j = i;
             while (j >  0  && tmp < array[j- 1 ]){ //從已經排序的序列最右邊的開始比較,找到比其小的數
                 array[j] = array[j- 1 ]; //向後挪動
                 j--;
             }
             array[j] = tmp; //存在比其小的數,插入
         }
         return  array;
     }
     
     //遍歷顯示數組
     public  static  void  display( int [] array){
         for ( int  i =  0  ; i < array.length ; i++){
             System.out.print(array[i]+ " " );
         }
         System.out.println();
     }
     
     public  static  void  main(String[] args){
         int [] array = { 4 , 2 , 8 , 9 , 5 , 7 , 6 , 1 , 3 };
         //未排序數組順序爲
         System.out.println( "未排序數組順序爲:" );
         display(array);
         System.out.println( "-----------------------" );
         array = sort(array);
         System.out.println( "-----------------------" );
         System.out.println( "通過插入排序後的數組順序爲:" );
         display(array);
     }
 
}

  運行結果:

  

  插入排序性能分析:

  在第一輪排序中,它最多比較一次,第二輪最多比較兩次,一次類推,第N輪,最多比較N-1次。所以有 1+2+3+...+N-1 = N*(N-1)/2。

  假設在每一輪排序發現插入點時,平均只有全體數據項的一半真的進行了比較,咱們除以2獲得:N*(N-1)/4。用大O表示法大體須要須要 O(N2) 時間級別。

  複製的次數大體等於比較的次數,可是一次複製與一次交換的時間耗時不一樣,因此相對於隨機數據,插入排序比冒泡快一倍,比選擇排序略快。

  這裏須要注意的是,若是要進行逆序排列,那麼每次比較和移動都會進行,這時候並不會比冒泡排序快。

 

四、總結

  上面講的三種排序,冒泡、選擇、插入用大 O 表示法都須要 O(N2) 時間級別。通常不會選擇冒泡排序,雖然冒泡排序書寫是最簡單的,可是平均性能是沒有選擇排序和插入排序好的。

  選擇排序把交換次數下降到最低,可是比較次數仍是挺大的。當數據量小,而且交換數據相對於比較數據更加耗時的狀況下,能夠應用選擇排序。

  在大多數狀況下,假設數據量比較小或基本有序時,插入排序是三種算法中最好的選擇。

  後面咱們會講解高級排序,大O表示法的時間級別將比O(N2)小。 

相關文章
相關標籤/搜索