1. 程式人生 > >[排序演算法]--氣泡排序的三種實現(Java)

[排序演算法]--氣泡排序的三種實現(Java)

氣泡排序是非常好理解的,以從小到大排序為例,每一輪排序就找出未排序序列中最大值放在最後。

設陣列的長度為N: (1)比較前後相鄰的二個數據,如果前面資料大於後面的資料,就將這二個數據交換。

(2)這樣對陣列的第0個數據到N-1個數據進行一次遍歷後,最大的一個數據就“沉”到陣列第N-1個位置。

(3)N=N-1,如果N不為0就重複前面二步,否則排序完成。

/**
 * 氣泡排序的第一種實現, 沒有任何優化
 * @param a
 * @param n
 */
public static void bubbleSort1(int [] a, int n){
    int i, j;

    for(i=0; i<n; i++){//表示n次排序過程。
        for(j=1; j<n-i; j++){
            if(a[j-1] > a[j]){//前面的數字大於後面的數字就交換
                //交換a[j-1]和a[j]
                int temp;
                temp = a[j-1];
                a[j-1] = a[j];
                a[j]=temp;
            }
        }
    }
}// end

給出一個測試程式碼:

public static void main(String[] args) {
    int[] arr = {1,1,2,0,9,3,12,7,8,3,4,65,22};

    BubbleSort.bubbleSort1(arr, arr.length);

    for(int i:arr){
        System.out.print(i+",");
    }
}

執行結果:

0,1,1,2,3,3,4,7,8,9,12,22,65,

下面開始考慮優化,如果對於一個本身有序的序列,或則序列後面一大部分都是有序的序列,上面的演算法就會浪費很多的時間開銷,這裡設定一個標誌flag,如果這一趟發生了交換,則為true,否則為false。明顯如果有一趟沒有發生交換,說明排序已經完成。

/**
 * 設定一個標誌,如果這一趟發生了交換,則為true,否則為false。明顯如果有一趟沒有發生交換,說明排序已經完成。
 * @param a
 * @param n
 */
public static void bubbleSort2(int [] a, int n){
    int j, k = n;
    boolean flag = true;//發生了交換就為true, 沒發生就為false,第一次判斷時必須標誌位true。
    while (flag){
        flag=false;//每次開始排序前,都設定flag為未排序過
        for(j=1; j<k; j++){
            if(a[j-1] > a[j]){//前面的數字大於後面的數字就交換
                //交換a[j-1]和a[j]
                int temp;
                temp = a[j-1];
                a[j-1] = a[j];
                a[j]=temp;

                //表示交換過資料;
                flag = true;
            }
        }
        k--;//減小一次排序的尾邊界
    }//end while
}//end

執行測試main函式結果:

0,1,1,2,3,3,4,7,8,9,12,22,65,

再進一步做優化。比如,現在有一個包含1000個數的陣列,僅前面100個無序,後面900個都已排好序且都大於前面100個數字,那麼在第一趟遍歷後,最後發生交換的位置必定小於100,且這個位置之後的資料必定已經有序了,也就是這個位置以後的資料不需要再排序了,於是記錄下這位置,第二次只要從陣列頭部遍歷到這個位置就可以了。如果是對於上面的氣泡排序演算法2來說,雖然也只排序100次,但是前面的100次排序每次都要對後面的900個數據進行比較,而對於現在的排序演算法3,只需要有一次比較後面的900個數據,之後就會設定尾邊界,保證後面的900個數據不再被排序。

public static void bubbleSort3(int [] a, int n){
    int j , k;
    int flag = n ;//flag來記錄最後交換的位置,也就是排序的尾邊界

    while (flag > 0){//排序未結束標誌
        k = flag; //k 來記錄遍歷的尾邊界
        flag = 0;

        for(j=1; j<k; j++){
            if(a[j-1] > a[j]){//前面的數字大於後面的數字就交換
                //交換a[j-1]和a[j]
                int temp;
                temp = a[j-1];
                a[j-1] = a[j];
                a[j]=temp;

                //表示交換過資料;
                flag = j;//記錄最新的尾邊界.
            }
        }
    }
}

這種方法是我看到的最優化的氣泡排序了。 執行測試例子結果:

0,1,1,2,3,3,4,7,8,9,12,22,65,
可知執行結果正確。