JS 這一次徹底理解冒泡排序


壹 ❀ 引

在面試環節中,算法總是逃不掉的一關,對於我這種非班科出生且大學不接觸數學的人來說,邏輯思維方面確實較為欠缺,昨晚跟百度的同學聊到凌晨,自我感覺差距較大,受了不小打擊,所以決心抓一抓算法,做做相關訓練題,我可能沒天賦,但做一點總比什么都不做要強,這篇文章從十大排序中的冒泡排序說起。

貳 ❀ 冒泡排序基本概念

在水中,空氣的密度比水輕,所以水中的氣泡會不斷上浮,這是我們生活中所理解的冒泡。而冒泡排序的概念也是如此。

對於一個數組,我們會比較相鄰的兩個元素,如果前者比后者大,則需要交換兩者的位置,也就是較大的后沉,較小的往前浮,看個最簡單的例子。

let arr = [2, 1];
//比較索引0,與索引1的兩個元素,如果前者比后者大,交換兩者位置。
if (arr[0] > arr[1]) {
    //交換位置
    arr[0] = [arr[1], arr[1] = arr[0]][0]
};
arr; //[1,2]

當然,這個例子特別簡單,因為只包含2個元素,所以我們只需要遍歷一次,且只比較一次即可得到最終排序結果。

我們將數組升級,再加一項:

let arr = [3,2,1];

此時只比較一次很明顯解決不了問題,不過數量不多,我們嘗試拆分比較過程。

  • 第一次遍歷
    • 第一次比較
      • 3比2大,交換位置,得到數組[2,3,1];
    • 第二次比較
      • 3比1大,再次交換位置,得到數組[2,1,3];

此時第一次遍歷結束,我們發現目前數組並沒有排序完成,還需要再遍歷一次:

  • 第二次遍歷
    • 第一次比較
      • 2比1大,交換位置,得到數組[1,2,3]

此時排序完成,為什么第二次只需要比較一次呢?這是因為第一次遍歷一定會將數組當前最大項移到數組尾部,所以第二次比較沒有意義。

為了論證這一點,我們將數組再次升級,再多加一項,拆分步驟如下:

let arr = [4,2,3,1];
  • 第一次遍歷
    • 第一次比較
      • 4比2大,交換位置,得到數組[2,4,3,1];
    • 第二次比較
      • 4比3大,交換位置,得到數組[2,3,4,1];
    • 第三次比較
      • 4比1大,交換位置,得到數組[2,3,1,4],此時第一次遍歷結束,看來還需要再次遍歷。
  • 第二次遍歷
    • 第一次比較
      • 2比3小,不需要交換位置,數組維持不變[2,3,1,4];
    • 第二次比較
      • 3比1大,交換位置,得到數組[2,1,3,4];

你看,我們又不需要進行第三次比較,因為第一次遍歷已經將最大的4移動到了數組末尾,所以第三次比較毫無意義。由於數組還沒排序完畢,我們需要進行第三次遍歷:

  • 第三次遍歷
    • 第一次比較
      • 2比1大,交換位置,得到數組[1,2,3,4];

此時我們已經得到了最終排序,所以不需要進行第二次比較與第三次比較。

細心的同學可能已經發現了一個規律,針對同一個數組,每遍歷一次,都會將當前最大的元素移動到數組末尾,且下次遍歷的比較次數需要相比上次少一次。

再說的直白點,還是上面的例子,第1遍歷需要比較3次,確定了當前最大數4。第二次遍歷只需要比較2次,確定了當前最大數3,第三次遍歷只需要比較1次,確定了當前最大數2。

我們綜合上訴三個例子來做個總結:

  • 數組有2項時,需要遍歷1次,比較1次。
  • 數組有3項時,需要遍歷2次,第一次比較2次,第二次比較1次。
  • 數組有4項時,需要遍歷3次,第一次比較3次,第二次比較2次,第三次比較1次。

我們好像得到了一個結論,當數組有N項時,需要遍歷N-1次,且每次遍歷的比較次數為N - 當前遍歷次數(也就是i+1,因為是從i=0開始,所以加個1)

所以我們可以用2個for循環,外層用於定義遍歷次數,內層用於定義比較次數。

叄 ❀ 冒泡排序實現

知道了這個規律,我們直接上代碼:

let arr = [3, 1, 5, 4, 7, 6, 0, 2];

function bubbleSort(arr) {
    var length = arr.length,
        i = 0;
    // 遍歷次數為length-1次
    for (; i < length - 1; i++) {
        // 當前遍歷的比較次數為length - 當前遍歷次數
        for (var j = 0; j < length - i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                arr[j] = [arr[j + 1], arr[j + 1] = arr[j]][0];
            };
        };
    };
    return arr;
};

bubbleSort(arr); //[0, 1, 2, 3, 4, 5, 6, 7]

百度百科給的代碼示例外層使用了while循環,思路一樣,代碼如下:

function bubbleSort(arr) {
    var i = arr.length, j;
    var tempExchangVal;
    while (i > 0) {
        for (j = 0; j < i - 1; j++) {
            if (arr[j] > arr[j + 1]) {
                tempExchangVal = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = tempExchangVal;
            };
        };
        i--;
    };
    return arr;
};
 
var arr = [3, 2, 4, 9, 1, 5, 7, 6, 8];

但是這段代碼有個問題,前面我們知道當數組有N項,就需要遍歷N-1次,很明顯這段代碼中使用while(i>0)會無意義的多執行一次,這里改成while(i>1)會好一點。

那么關於數組冒泡排序就說到這里,本人笨拙,為了解釋清楚冒泡的過程,只能采取找規律來加深理解,若文中有描述不當之處,還望指出,那么到這里本文結束。

肆 ❀ 參考

排序-冒泡排序
三分鍾徹底理解冒泡排序


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM