冒泡排序的基本思想是:每次比較兩個相鄰的元素,如果它們的順序錯誤就把它們交換過來。
例如我們需要將12 35 99 18 76 這5 個數進行從大到小的排序。既然是從大到小排序,也就是說越小的越靠后。
首先比較第1 位和第2 位的大小,現在第1 位是12,第2 位是35。發現12 比35 要小,因為我們希望越小越靠后嘛,因此需要交換這兩個數的位置。交換之后這5 個數的順序是35 12 99 18 76。
按照剛才的方法,繼續比較第2 位和第3 位的大小,第2 位是12,第3 位是99。12 比99 要小,因此需要交換這兩個數的位置。交換之后這5 個數的順序是35 99 12 18 76。
根據剛才的規則,繼續比較第3 位和第4 位的大小,如果第3 位比第4 位小,則交換位置。交換之后這5 個數的順序是35 99 18 12 76。
最后,比較第4 位和第5 位。4 次比較之后5 個數的順序是35 99 18 76 12。經過4 次比較后我們發現最小的一個數已經就位(已經在最后一位,請注意12 這個數的移動過程),是不是很神奇。現在再來回憶一下剛才比較的過程。每次都是比較相鄰的兩個數,如果后面的數比前面的數大,則交換這兩個數的位置。一直比較下去直到最后兩個數比較完畢后,最小的數就在最后一個了。就如同是一個氣泡,一步一步往后“翻滾”,直到最后一位。所以這個排序的方法有一個很好聽的名字“冒泡排序”。
說到這里其實我們的排序只將5 個數中最小的一個歸位了。每將一個數歸位我們將其稱為“一趟”。下面我們將繼續重復剛才的過程,將剩下的4 個數一一歸位。
好,現在開始“第二趟”,目標是將第2 小的數歸位。首先還是先比較第1 位和第2 位,如果第1 位比第2 位小,則交換位置。交換之后這5 個數的順序是99 35 18 76 12。接下來你應該都會了,依次比較第2 位和第3 位,第3 位和第4 位。注意此時已經不需要再比較第4位和第5 位。因為在第一趟結束后已經可以確定第5 位上放的是最小的了。第二趟結束之后這5 個數的順序是99 35 76 18 12。
“第三趟”也是一樣的。第三趟之后這5 個數的順序是99 76 35 18 12。現在到了最后一趟“第四趟”。有的同學又要問了,這不是已經排好了嗎?還要繼續?當然,這里純屬巧合,你若用別的數試一試可能就不是了。你能找出這樣的數據樣例來嗎?
請試一試。
“冒泡排序”的原理是:每一趟只能確定將一個數歸位。即第一趟只能確定將末位上的數(即第5 位)歸位,第二趟只能將倒數第2 位上的數(即第4 位)歸位,第三趟只能將倒數第3 位上的數(即第3 位)歸位,而現在前面還有兩個位置上的數沒有歸位,因此我們仍然需要進行“第四趟”。“第四趟”只需要比較第1 位和第2 位的大小。因為后面三個位置上的數歸位了,現在第1 位是99,第2 位是76,無需交換。這5 個數的順序不變仍然是99 76 35 18 12。到此排 序完美結束了,5 個數已經有4 個數歸位,那最后一個數也只能放在第1 位了。 最后我們總結一下:如果有n 個數進行排序,只需將n?1 個數歸位,也就是說要進行n-1 趟操作。而“每一趟”都需要從第1 位開始進行相鄰兩個數的比較,將較小的一個數放在后面,比較完畢后向后挪一位繼續比較下面兩個相鄰數的大小,重復此步驟,直到最后一個尚未歸位的數,已經歸位的數則無需再進行比較(已經歸位的數你還比較個啥,浪費表情)。這個算法是不是很強悍?記得我每次拍集體照的時候就總是被別人換來換去的,當時特別煩。不知道發明此算法的人當時的靈感是否來源于此。啰里吧嗦地說了這么多,下面是代碼。建議先自己嘗試去實現一下看看,再來看我是如何實現的。
```
public class BubbleSort{
public static void main(String[] args){
int score[] = {67, 69, 75, 87, 89, 90, 99, 100};
for (int i = 0; i < score.length -1; i++){? ? //最多做n-1趟排序
for(int j = 0 ;j < score.length - i - 1; j++){? ? //對當前無序區間score[0......length-i-1]進行排序(j的范圍很關鍵,這個范圍是在逐步縮小的)
if(score[j] < score[j + 1]){? ? //把小的值交換到后面
int temp = score[j];
score[j] = score[j + 1];
score[j + 1] = temp;
}
}
System.out.print("第" + (i + 1) + "次排序結果:");
for(int a = 0; a < score.length; a++){
System.out.print(score[a] + "\t");
}
System.out.println("");
}
System.out.print("最終排序結果:");
for(int a = 0; a < score.length; a++){
System.out.print(score[a] + "\t");
}
}
}
```
冒泡排序的核心部分是雙重嵌套循環。不難看出冒泡排序的時間復雜度是O(N2)。這是一個非常高的時間復雜度。冒泡排序早在1956 年就有人開始研究,之后有很多人都嘗試過對冒泡排序進行改進,但結果卻令人失望。如Donald E. Knuth(中文名為高德納,1974 年圖靈獎獲得者)所說:“冒泡排序除了它迷人的名字和導致了某些有趣的理論問題這一事實之外,似乎沒有什么值得推薦的。”你可能要問:那還有沒有更好的排序算法呢?不要走開,請看下節——快速排序。