天天看點

排序一 冒泡排序要點算法分析優化完整參考代碼

冒泡排序是一種交換排序。

什麼是交換排序呢?

交換排序:兩兩比較待排序的關鍵字,并交換不滿足次序要求的那對數,直到整個表都滿足次序要求為止。

它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。

這個算法的名字由來是因為越小的元素會經由交換慢慢“浮”到數列的頂端,故名。

假設有一個大小為 N 的無序序列。冒泡排序就是要每趟排序過程中通過兩兩比較,找到第 i 個小(大)的元素,将其往上排。

排序一 冒泡排序要點算法分析優化完整參考代碼

圖-冒泡排序示例圖

以上圖為例,示範一下冒泡排序的實際流程:

假設有一個無序序列  { 4. 3. 1. 2, 5 }

第一趟排序:通過兩兩比較,找到第一小的數值 1 ,将其放在序列的第一位。

第二趟排序:通過兩兩比較,找到第二小的數值 2 ,将其放在序列的第二位。

第三趟排序:通過兩兩比較,找到第三小的數值 3 ,将其放在序列的第三位。

至此,所有元素已經有序,排序結束。 

要将以上流程轉化為代碼,我們需要像機器一樣去思考,不然編譯器可看不懂。

假設要對一個大小為 N 的無序序列進行升序排序(即從小到大)。 

(1) 每趟排序過程中需要通過比較找到第 i 個小的元素。

是以,我們需要一個外部循環,從數組首端(下标 0) 開始,一直掃描到倒數第二個元素(即下标 N - 2) ,剩下最後一個元素,必然為最大。

(2) 假設是第 i 趟排序,可知,前 i-1 個元素已經有序。現在要找第 i 個元素,隻需從數組末端開始,掃描到第 i 個元素,将它們兩兩比較即可。

是以,需要一個内部循環,從數組末端開始(下标 N - 1),掃描到 (下标 i + 1)。

核心代碼

<a></a>

public void bubbleSort(int[] list) {

    int temp = 0; // 用來交換的臨時數

    // 要周遊的次數

    for (int i = 0; i &lt; list.length - 1; i++) {

        // 從後向前依次的比較相鄰兩個數的大小,周遊一次後,把數組中第i小的數放在第i個位置上

        for (int j = list.length - 1; j &gt; i; j--) {

            // 比較相鄰的元素,如果前面的數大于後面的數,則交換

            if (list[j - 1] &gt; list[j]) {

                temp = list[j - 1];

                list[j - 1] = list[j];

                list[j] = temp;

            }

        }

        System.out.format("第 %d 趟:\t", i);

        printAll(list);

    }

}

排序類别

排序方法

時間複雜度

空間複雜度

穩定性

複雜性

平均情況

最壞情況

最好情況

交換排序

冒泡排序

O(N2)

O(N)

O(1)

穩定

簡單

若檔案的初始狀态是正序的,一趟掃描即可完成排序。所需的關鍵字比較次數C和記錄移動次數M均達到最小值:Cmin = N - 1, Mmin = 0。是以,冒泡排序最好時間複雜度為O(N)。

若初始檔案是反序的,需要進行 N -1 趟排序。每趟排序要進行 N - i 次關鍵字的比較(1 ≤ i ≤ N - 1),且每次比較都必須移動記錄三次來達到交換記錄位置。在這種情況下,比較和移動次數均達到最大值:

Cmax = N(N-1)/2 = O(N2)

Mmax = 3N(N-1)/2 = O(N2)

冒泡排序的最壞時間複雜度為O(N2)。

是以,冒泡排序的平均時間複雜度為O(N2)。

總結起來,其實就是一句話:當資料越接近正序時,冒泡排序性能越好。

冒泡排序就是把小的元素往前調或者把大的元素往後調。比較是相鄰的兩個元素比較,交換也發生在這兩個元素之間。

是以相同元素的前後順序并沒有改變,是以冒泡排序是一種穩定排序算法。

對冒泡排序常見的改進方法是加入标志性變量exchange,用于标志某一趟排序過程中是否有資料交換。

如果進行某一趟排序時并沒有進行資料交換,則說明所有資料已經有序,可立即結束排序,避免不必要的比較過程。

// 對 bubbleSort 的優化算法

public void bubbleSort_2(int[] list) {

    boolean bChange = false; // 交換标志

        bChange = false;

                bChange = true;

        // 如果标志為false,說明本輪周遊沒有交換,已經是有序數列,可以結束排序

        if (false == bChange)

            break;

代碼實作

 View Code

運作結果

排序前:      2    9    9    7    1    9    0    2    6    8   

第 0 趟:    0    2    9    9    7    1    9    2    6    8   

第 1 趟:    0    1    2    9    9    7    2    9    6    8   

第 2 趟:    0    1    2    2    9    9    7    6    9    8   

第 3 趟:    0    1    2    2    6    9    9    7    8    9   

第 4 趟:    0    1    2    2    6    7    9    9    8    9   

第 5 趟:    0    1    2    2    6    7    8    9    9    9   

排序後:      0    1    2    2    6    7    8    9    9    9  

本文轉自靜默虛空部落格園部落格,原文連結:http://www.cnblogs.com/jingmoxukong/p/4302718.html,如需轉載請自行聯系原作者

繼續閱讀