動畫:一篇文章快速學會冒泡排序

內容介紹

冒泡排序原理

冒泡排序(Bubble Sort)是一種交換排序,它的基本思想是:兩兩比較相鄰的數據,大的日後放。java

你們必定看過水中的氣泡,小氣泡一點一點向上浮動變成大氣泡。 算法

冒泡排序這個算法的名字由來是由於元素像水中的氣泡冒泡同樣,小的元素會通過交換慢慢「浮」到數列的一端。咱們來看冒泡排序的動畫演示。 編程

冒泡排序的分析

通常沒有特殊要求排序算法都是升序排序,小的在前,大的在後。數組由{6, 5, 4, 1, 3, 2}這6個無序元素組成。數組

冒泡排序交換過程圖示(第一輪): 微信

第一次相鄰的元素6和元素5比較,發現前面的元素大於後面的元素,交換位置。 優化

交換後 動畫

第二次相鄰的元素6和元素4比較,發現前面的元素大於後面的元素,交換位置。 code

交換後 blog

第三次相鄰的元素6和元素1比較,發現前面的元素大於後面的元素,交換位置。 排序

交換後

第四次相鄰的元素6和元素3比較,發現前面的元素大於後面的元素,交換位置。

交換後

第五次相鄰的元素6和元素2比較,發現前面的元素大於後面的元素,交換位置。

交換後

通過第一輪的五次比較,元素6由數組的最前面冒泡到數組的最後面。最大的元素就在數組的最後面。注意觀察,通過一輪比較只能將參數比較的數字中的最大的數字冒泡到右邊,其他的仍是無序的。所以須要進行多輪比較才能將數組變成有序的。

冒泡排序交換過程圖示(第二輪):

通過第二輪的四次比較,元素5由數組的最前面冒泡到數組的倒數第二的位置。大的元素就在數組的後面。數組最後面的元素5和元素6能夠比較也能夠不比較,對結果沒有影響。到時候咱們寫代碼的時候注意一下便可。

冒泡排序交換過程圖示(第三輪):

交換過程和前兩輪分析的相似,咱們省略過程,最終第三輪交換後的結果:

冒泡排序交換過程圖示(第四輪):

交換過程和前兩輪分析的相似,咱們省略過程,最終第四輪交換後的結果:

冒泡排序交換過程圖示(第五輪):

第五輪比價元素1和元素2,這兩個元素自己已經有序了,因此沒有變化,最終第五輪交換後的結果和第四輪同樣:

到此爲止,全部元素都是有序的了,這就是冒泡排序的總體過程。

冒泡排序代碼編寫

咱們發現每一輪都須要從索引0開始,相鄰元素兩比較,須要使用一個循環(內循環)控制每輪的比較元素。另外數組6個元素須要通過五輪比較,也須要使用一個循環(外循環)控制比較的輪數,並且比較的輪數是元素的數量-1。

public class BubbleSortTest {
    public static void main(String[] args) {
        int[] arr = new int[]{6, 5, 4, 1, 3, 2};
        System.out.println("排序前數組" + Arrays.toString(arr));
        bubbleSort1(arr);
    }

    // 冒泡排序
    public static void bubbleSort1(int[] arr) {
        for (int i = 0; i < arr.length - 1; i++) { // 外循環控制比較的輪數,輪數是元素的數量-1
            for (int j = 0; j < arr.length - 1 - i; j++) { // 內循環控制每輪比較的元素,輪數越大,比較的次數越少
                if (arr[j] > arr[j+1]) { // i和i+1索引比較,也就是相鄰元素比較,大的日後放
                    System.out.print("\t元素 " + arr[j] + " 和 " + arr[j+1] + " 比較, ");
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    System.out.println("比較後" + Arrays.toString(arr));
                }
            }
            System.out.println("排序" + (i+1) + "輪後: " + Arrays.toString(arr));
        }
    }
}

運行效果以下:

排序前數組[6, 5, 4, 1, 3, 2]
	元素 6 和 5 比較, 比較後[5, 6, 4, 1, 3, 2]
	元素 6 和 4 比較, 比較後[5, 4, 6, 1, 3, 2]
	元素 6 和 1 比較, 比較後[5, 4, 1, 6, 3, 2]
	元素 6 和 3 比較, 比較後[5, 4, 1, 3, 6, 2]
	元素 6 和 2 比較, 比較後[5, 4, 1, 3, 2, 6]
排序1輪後: [5, 4, 1, 3, 2, 6]
	元素 5 和 4 比較, 比較後[4, 5, 1, 3, 2, 6]
	元素 5 和 1 比較, 比較後[4, 1, 5, 3, 2, 6]
	元素 5 和 3 比較, 比較後[4, 1, 3, 5, 2, 6]
	元素 5 和 2 比較, 比較後[4, 1, 3, 2, 5, 6]
排序2輪後: [4, 1, 3, 2, 5, 6]
	元素 4 和 1 比較, 比較後[1, 4, 3, 2, 5, 6]
	元素 4 和 3 比較, 比較後[1, 3, 4, 2, 5, 6]
	元素 4 和 2 比較, 比較後[1, 3, 2, 4, 5, 6]
排序3輪後: [1, 3, 2, 4, 5, 6]
	元素 3 和 2 比較, 比較後[1, 2, 3, 4, 5, 6]
排序4輪後: [1, 2, 3, 4, 5, 6]
排序5輪後: [1, 2, 3, 4, 5, 6]

這是最原始的冒泡排序,該排序算法的每一輪要遍歷全部元素,而且輪數和元素數量只少1,時間複雜度: 最優時間複雜度:O(n^2) (即便元素有序仍是須要進行比較) 最壞時間複雜度:O(n^2) 穩定性:穩定

這個算法的效率是很是低的。

冒泡排序代碼優化1

優化1: 若是有一輪發現沒有須要排序的,說明已經有序了,能夠不用再遍歷比較了。以下圖所示,第一輪比較事後,第二輪比較時發現元素已經所有是有序的,直接退出就沒有必要再進行後面第三,第四,五輪的比較了。

代碼以下:

public class BubbleSortTest2 {
    public static void main(String[] args) {
        int[] arr = new int[]{1, 3, 2, 4, 5, 6};
        System.out.println("排序前數組" + Arrays.toString(arr));
        bubbleSort2(arr);
    }

    // 優化1:若是有一輪發現沒有須要排序的,說明已經有序了.能夠不用再遍歷比較了
    public static void bubbleSort2(int[] arr) { // 0.132s
        for (int i = 0; i < arr.length - 1; i++) {
            boolean sorted = true; // 用於標記數組是否有序,若是這輪一個元素都沒有交換說明有序,後面幾輪不須要在排序了
            for (int j = 0; j < arr.length - 1 - i; j++) {
                if (arr[j] > arr[j+1]) {
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    sorted = false; // 有元素須要交換,說明數組仍是無序的.
                }
            }
            if (sorted) {
                System.out.println("已經有序了, length = " + arr.length + ", 第 " + (i+1) + "輪");
                break;
            }
        }
    }
}

運行效果以下:

排序前數組[1, 3, 2, 4, 5, 6]
已經有序了, length = 6, 第 2輪

利用布爾變量sorted做爲標記。若是在本輪排序中,沒有元素交換,說明數組已經有序,直接跳出大循環。通過此次優化後,若是數組已經有順序了,能夠減小比較的輪數。

冒泡排序代碼優化2

優化2: 問題是在於j<array.length– i– 1。每輪都會比較到array.length– i– 1這個位置,若是後面已是有序的就不須要比較,下一輪只須要比較到上一輪的最後一次交換的小值那個地方便可,減小每輪的比較次數。

優化前第二輪須要比較到索引4的位置,優化後第二輪只須要比較到上次最後比較的那個位置,也就是lastPosition的位置

代碼以下:

public class BubbleSortTest2 {
    public static void main(String[] args) {
        int[] arr = new int[]{3, 2, 1, 4, 5, 6, 7};

        System.out.println("排序前數組" + Arrays.toString(arr));
        bubbleSort3(arr);
    }

    // 優化2:問題是在於j<array.length– i– 1。若是後面已是有序的就不須要比較
    // 下一輪只須要比較到上一輪的最後一次交換的小值那個地方便可
    public static void bubbleSort3(int[] arr) { // 0.132s
        int lastPosition = 0; // 記錄這一輪最後一次比較的較小那個值,下一輪就比較到這裏
        int len = arr.length - 1; // len表示下一輪要比較到哪裏?後面會讓len = lastPosition
        for (int i = 0; i < arr.length - 1; i++) {
            boolean sorted = true; // 用於標記數組是否有序,若是這輪一個元素都沒有交換說明有序,後面幾輪不須要在排序了
            for (int j = 0; j < len; j++) {
                if (arr[j] > arr[j+1]) {
                    int temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                    sorted = false; // 有元素須要交換,說明數組仍是無序的.
                    lastPosition = j; // 記錄這一輪最後一次比較的較小那個值,下一輪就比較到這裏
                } else {
                    System.out.println("第 " + i + " 輪的第 " + j + " 次不須要交換");
                }
            }
            len = lastPosition;
            if (sorted) {
                System.out.println("已經有序了, length = " + arr.length + ", i = " + i);
                break;
            }
        }
    }
}

冒泡排序複雜度

這是最原始的冒泡排序,該排序算法的每一輪要遍歷全部元素,而且輪數和元素數量只少1,時間複雜度:

  1. 最優時間複雜度:O(n) 當數據自己已經有序如:{1, 2, 3, 4, 5, 6},咱們作了優化,比較一輪就結束。
  2. 最壞時間複雜度:O(n^2) 當數據自己是倒序的如:{6, 5, 4, 3, 2, 1},總執行次數爲n^2-n。
  3. 平均時間複雜度:O(n^2)。
  4. 穩定性:穩定

總結

冒泡排序是一種交換排序,它的基本思想是:兩兩比較相鄰的數據,大的日後放。使用嵌套循環來實現冒泡排序,外循環控制比較的輪數,內循環控制每輪比較的次數。 冒泡排序能夠進行兩個優化:

  1. 若是有一輪發現沒有須要排序的,說明已經有序了,能夠不用再遍歷比較了,減小比較輪數。
  2. 每輪都會比較到array.length– i– 1這個位置,若是後面已是有序的就不須要比較,下一輪只須要比較到上一輪的最後一次交換的小值那個地方便可,減小每輪的比較次數。

原創文章和動畫製做真心不易,您的點贊就是最大的支持! 想了解更多文章請關注微信公衆號:表哥動畫學編程

相關文章
相關標籤/搜索