????????人們開始學(xué)習(xí)排序算法時,通常都先學(xué)冒泡算法,因為它在所有排序算法中最簡單。然而,從運行時間的角度來看,冒泡排序是最差的一個,接下來你會知曉原因。
????????冒泡排序比較任何兩個相鄰的項,如果第一個比第二個大,則交換它們。元素項向上移動至正確的順序,就好像氣泡升至表面一樣,冒泡排序因此得名。
讓我們來實現(xiàn)一下冒泡排序:
this.bubbleSort = function(){
????var length = array.length; //{1}
????for (var i=0; i<length; i++){ //{2}
????????for (var j=0; j<length-1; j++ ){ //{3}
????????????if (array[j] > array[j+1]){ //{4}
????????????????swap(array, j, j+1); //{5}
????????????}
????????}
????}
};
????????首先,聲明一個名為 length 的變量,用來存儲數(shù)組的長度(行 {1} )。這一步可選,它能幫助我們在行 {2} 和行 {3} 時直接使用數(shù)組的長度。接著,外循環(huán)(行 {2} )會從數(shù)組的第一位迭代至最后一位,它控制了在數(shù)組中經(jīng)過多少輪排序(應(yīng)該是數(shù)組中每項都經(jīng)過一輪,輪數(shù)和數(shù)組長度一致)。然后,內(nèi)循環(huán)將從第一位迭代至倒數(shù)第二位,內(nèi)循環(huán)實際上進(jìn)行當(dāng)前項和下一項的比較(行 {4} )。如果這兩項順序不對(當(dāng)前項比下一項大),則交換它們(行 {5} ),意思是位置為j+1 的值將會被換置到位置 j 處,反之亦然。
????????現(xiàn)在我們得聲明 swap 函數(shù)(一個私有函數(shù),只能用在 ArrayList 類的內(nèi)部代碼中):
var swap = function(array, index1, index2){
????var aux = array[index1];
????array[index1] = array[index2];
????array[index2] = aux;
};
????????交換時,我們用一個中間值來存儲某一交換項的值。其他排序法也會用到這個方法,因此我們聲明一個方法放置這段交換代碼以便重用。
????????如果使用在第1章學(xué)過的ES6(ECMAScript 2015)增強(qiáng)的對象屬性,這個函數(shù)可以寫成下面這樣:
? ?[array[index1], array[index2]] = [array[index2], array[index1]];
????????下面這個示意圖展示了冒泡排序的工作過程:
????????該示意圖中每一小段表示外循環(huán)的一輪(行 {2} ),而相鄰兩項的比較則是在內(nèi)循環(huán)中進(jìn)行的(行 {3} )。
????????我們將使用下面這段代碼來測試冒泡排序算法,看結(jié)果是否和示意圖所示一致:
function createNonSortedArray(size){ //{6}
????var array = new ArrayList();
????for (var i = size; i> 0; i--){
????????array.insert(i);
????}
????return array;
}
var array = createNonSortedArray(5); //{7}
console.log(array.toString()); //{8}
array.bubbleSort(); //{9}
console.log(array.toString()); //{10}
????????為了輔助測試本章將要學(xué)習(xí)的排序算法,我們將創(chuàng)建一個函數(shù)來自動地創(chuàng)建一個未排序的數(shù)組,數(shù)組的長度由函數(shù)參數(shù)指定(行 {6} )。如果傳遞 5 作為參數(shù),該函數(shù)會創(chuàng)建如下數(shù)組: [5, 4,3, 2, 1] 。調(diào)用這個函數(shù)并將返回值存儲在一個變量中,該變量將包含這個以某些數(shù)字來初始化的 ArrayList 類實例(行 {7} )。我們在控制臺上輸出這個數(shù)組內(nèi)容,確保這是一個未排序數(shù)組(行 {8} ),接著我們調(diào)用冒泡排序方法(行 {9} )并再次在控制臺上輸出數(shù)組內(nèi)容以驗證數(shù)組已被排序了(行 {10} )。
? ??????注意當(dāng)算法執(zhí)行外循環(huán)的第二輪的時候,數(shù)字4和5已經(jīng)是正確排序的了。盡管如此,在后續(xù)比較中,它們還一直在進(jìn)行著比較,即使這是不必要的。因此,我們可以稍稍改進(jìn)一下冒泡排序算法。
????????改進(jìn)后的冒泡排序
????????如果從內(nèi)循環(huán)減去外循環(huán)中已跑過的輪數(shù),就可以避免內(nèi)循環(huán)中所有不必要的比較(行 {1} )
this.modifiedBubbleSort = function(){
????var length = array.length;
????for (var i=0; i<length; i++){
????????for (var j=0; j<length-1-i; j++ ){ //{1}
????????????if (array[j] > array[j+1]){
????????????????swap(j, j+1);
????????????}
????????}
????}
};
????????下面這個示意圖展示了改進(jìn)后的冒泡排序算法是如何執(zhí)行的: