[排序演算法]--氣泡排序的三種實現(Java)
阿新 • • 發佈:2018-12-14
氣泡排序是非常好理解的,以從小到大排序為例,每一輪排序就找出未排序序列中最大值放在最後。
設陣列的長度為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,
可知執行結果正確。