介紹 :
冒泡排序(Bubble Sort),是一種計算機科學領域的較簡單的排序算法。
它重復地走訪過要排序的元素列,依次比較兩個相鄰的元素,如果順序(如從大到小、首字母從Z到A)錯誤就把他們交換過來。走訪元素的工作是重復地進行直到沒有相鄰元素需要交換,也就是說該元素列已經排序完成。
這個算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端(升序或降序排列),就如同碳酸飲料中二氧化碳的氣泡最終會上浮到頂端一樣,故名“冒泡排序”。
算法原理 :
-
比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。
-
對每一對相鄰元素做同樣的工作,從開始第一對到結尾的最后一對。在這一點,最后的元素應該會是最大的數。
-
針對所有的元素重復以上的步驟,除了最后一個。
-
持續每次對越來越少的元素重復上面的步驟,直到沒有任何一對數字需要比較。
動圖演示 :
算法穩定性 :
冒泡排序就是把小的元素往前調或者把大的元素往后調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。所以,如果兩個元素相等,是不會再交換的;如果兩個相等的元素沒有相鄰,那么即使通過前面的兩兩交換把兩個相鄰起來,這時候也不會交換,所以相同元素的前后順序並沒有改變,所以冒泡排序是一種穩定排序算法。
時間復雜度 :
1.如果我們的數據正序,只需要走一趟即可完成排序。所需的比較次數 C 和記錄移動次數 M 均達到最小值,即:Cmin=n-1 ; Mmin=0 ; 所以,冒泡排序最好的時間復雜度為 O(n) 。
2.如果很不幸我們的數據是反序的,則需要進行 n-1 趟排序。每趟排序要進行 n-i 次比較 ( 1 ≤ i ≤ n-1 ),且每次比較都必須移動記錄三次來達到交換記錄位置。在這種情況下,比較和移動次數均達到最大值:
綜上所述:冒泡排序總的平均時間復雜度為:O(n2) ,時間復雜度和數據狀況無關。
Java代碼 :
import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.Arrays; /** * 冒泡排序 */ public class BubbleSort { private static Log log = LogFactory.getLog (BubbleSort.class); public static void main(String[] args) { int size = 10;// 數組長度(0 - 10) int value = 100;// 值大小(-100 - 100) int[] arr = generateRandomArray (size, value); // 對象拷貝:一維數組:深克隆(重新分配空間,並將元素復制過去) int[] bubbleArr = arr.clone (); int[] sortArr = arr.clone (); StringBuilder arrStr = new StringBuilder ("原數組: "); for (int number : arr) { arrStr.append (number).append (" "); } log.info (arrStr); bubbleSort (bubbleArr); StringBuilder bubbleStr = new StringBuilder ("冒泡排序:"); for (int bValue : bubbleArr) { bubbleStr.append (bValue).append (" "); } log.info (bubbleStr); // 絕對正確的方法,這個方法可以時間復雜度很差,但是要保證其准確性 Arrays.sort (sortArr);// 調用系統的函數來進行驗證 StringBuilder sortStr = new StringBuilder ("系統函數排序: "); for (int sValue : sortArr) { sortStr.append (sValue).append (" "); } log.info (sortStr); log.info (isEqual (bubbleArr, sortArr) ? "成功" : "失敗"); } private static boolean isEqual(int[] arr1, int[] arr2) { for (int i = 0; i < arr1.length; i++) { if (arr1[i] != arr2[i]) { return false; } } return true; } //N個數字冒泡排序,總共要進行N-1趟比較,每趟的排序次數為(N-i)次比較 private static void bubbleSort(int[] arr) { //判斷邊界條件 if (arr == null || arr.length < 2) { return; } log.info ("數組長度: " + arr.length + ", 預計執行" + (arr.length - 1) + "輪排序"); boolean flag = false;// 判斷是否發生交換 for (int i = 0; i < arr.length - 1; i++) { log.info ("=========第" + (i+1) + "輪比較"); for (int j = 0; j < arr.length - i - 1; j++) { // 開始進行比較,如果arr[j]比arr[j+1]的值大,那就交換位置 if (arr[j] > arr[j + 1]) { int temp = arr[j]; arr[j] = arr[j + 1]; arr[j + 1] = temp; flag = true;// 發生交換 } StringBuilder sb = new StringBuilder (); sb.append ("第").append (j+1).append ("次比較:"); for (int number : arr) { sb.append (number).append (" "); } log.info (sb); } if (!flag) { log.info ("flag為false,未發生交換,數組有序,退出冒泡排序"); break; } flag = false; } } //生成一個對數器。產生一個隨機樣本的數組,數組的長度和值都是隨機的 private static int[] generateRandomArray(int size, int value) { // 生成長度隨機的數組,數組的最大長度是size的長度 int[] arr = new int[(int) ((size + 1) * Math.random ())]; for (int i = 0; i < arr.length; i++) { //針對數組中的每個值都可以隨機一下,一個隨機數減去另外一個隨機數,可能產生正數,也可能產生負數 arr[i] = (int) ((value + 1) * Math.random ()) - (int) (value * Math.random ()); } return arr; } }