壹 ❀ 引
在面試環節中,算法總是逃不掉的一關,對於我這種非班科出生且大學不接觸數學的人來說,邏輯思維方面確實較為欠缺,昨晚跟百度的同學聊到凌晨,自我感覺差距較大,受了不小打擊,所以決心抓一抓算法,做做相關訓練題,我可能沒天賦,但做一點總比什么都不做要強,這篇文章從十大排序中的冒泡排序說起。
貳 ❀ 冒泡排序基本概念
在水中,空氣的密度比水輕,所以水中的氣泡會不斷上浮,這是我們生活中所理解的冒泡。而冒泡排序的概念也是如此。
對於一個數組,我們會比較相鄰的兩個元素,如果前者比后者大,則需要交換兩者的位置,也就是較大的后沉,較小的往前浮,看個最簡單的例子。

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比2大,交換位置,得到數組
- 第二次比較
- 3比1大,再次交換位置,得到數組
[2,1,3]
;
- 3比1大,再次交換位置,得到數組
- 第一次比較
此時第一次遍歷結束,我們發現目前數組並沒有排序完成,還需要再遍歷一次:
- 第二次遍歷
- 第一次比較
- 2比1大,交換位置,得到數組
[1,2,3]
;
- 2比1大,交換位置,得到數組
- 第一次比較
此時排序完成,為什么第二次只需要比較一次呢?這是因為第一次遍歷一定會將數組當前最大項移到數組尾部,所以第二次比較沒有意義。
為了論證這一點,我們將數組再次升級,再多加一項,拆分步驟如下:
let arr = [4,2,3,1];
- 第一次遍歷
- 第一次比較
- 4比2大,交換位置,得到數組
[2,4,3,1]
;
- 4比2大,交換位置,得到數組
- 第二次比較
- 4比3大,交換位置,得到數組
[2,3,4,1]
;
- 4比3大,交換位置,得到數組
- 第三次比較
- 4比1大,交換位置,得到數組
[2,3,1,4]
,此時第一次遍歷結束,看來還需要再次遍歷。
- 4比1大,交換位置,得到數組
- 第一次比較
- 第二次遍歷
- 第一次比較
- 2比3小,不需要交換位置,數組維持不變
[2,3,1,4]
;
- 2比3小,不需要交換位置,數組維持不變
- 第二次比較
- 3比1大,交換位置,得到數組
[2,1,3,4]
;
- 3比1大,交換位置,得到數組
- 第一次比較
你看,我們又不需要進行第三次比較,因為第一次遍歷已經將最大的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)
會好一點。
那么關於數組冒泡排序就說到這里,本人笨拙,為了解釋清楚冒泡的過程,只能采取找規律來加深理解,若文中有描述不當之處,還望指出,那么到這里本文結束。