冒泡排序有多種不同的寫法,其中主要的區別就是性能的不同
這篇文章將逐步改進冒泡排序,使得冒泡排序不斷進化
原始人
先看代碼
public void getSortArray(int array[]) {
int temp = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
}
原始人的代碼就是簡單 ,簡單看看就能看的差不多,這裏面有一個很重要的地方:i 與 j 的取值問題
我當時看到代碼時不僅要問,i 與 j 爲什麼要這樣取值呢?
答曰:
-
對於 i 的 取值 :冒泡排序的目的就是 通過每次的交換,將最大的值交換到一串數字的最後,因爲 i 是最外層循環的控制變量,因此 i 就代表着循環的次數,假設外層循環了3次 ,那麼這串數字的最後3個數就已經有序了。所以,如果這串數字長度爲 n ,那麼顯然外層只要循環 n - 1 次就使得數列有序了。因此外層循環次數爲 array.length -1 次。
-
對於 j 的取值:n 次外層循環使得數列最後 n 個爲有序而且有序區的每個數必然比前面的都大,因此在每次的內層循環,沒有必要再讓 j 從 0 --> array.length - 1,只要從 0 --> array.length - i - 1
原始人進化
先看代碼
public void secondSortArray(int array[]) {
int temp = 0;
boolean sorted = false;
for (int i = 0; i < array.length - 1; i++) {
sorted = false;
for (int j = 0; j < array.length - i - 1; j++) {
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
sorted = true;
}
}
if(sorted == false) {
break;
}
}
}
最重要的就是添加了 sorted 這個布爾變量
爲什麼要添加這個變量呢?
看一個數列:1 2 3 4 5 8 7 顯然這個序列只通過一次就可以有序,但是實際上要經過 21 次循環
- 求冒泡排序(原始人階段) 的計算公式:n(n-1)/ 2 其中 n 爲數列的長度
這顯然太耗費時間了,加上一個布爾變量,如果一次內部循環沒有經過變量交換,那麼就說明已經排序完成了,因此就結束排序。
原始人再進化
看代碼
public void thirdSortArray(int array[]) {
int temp = 0;
int count = 0;
int boundary = array.length - 1;
boolean sorted = false;
for (int i = 0; i < array.length - 1; i++) {
sorted = false;
for (int j = 0; j < boundary; j++) {
count++;
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
sorted = true;
boundary = j;
}
}
if (sorted == false) {
break;
}
}
}
例如 2 1 3 5 6 7 8 這個數列,如果讓我們人來進行排序,那麼你會怎麼做?我們會找一個邊界,這個邊界的右側都是比左側大的數而且已經有序,此後就只看這個邊界左側的數字。
那麼把這個事情交給程序呢?我們也需要讓程序找到這個邊界,這個邊界找到了,那麼此後程序再進行數字比較的時候就更加省時省力。
如何讓程序找到這個邊界?重中之重就是:找到最後一次進行兩數字交換的位置,這個位置就是邊界!
知道了這裏,那麼代碼也就很好看懂了(代碼引進了第一次進化)
爲了說明三者之間效率的差距,在內層循環設置一個變量count 計算整個排序過程的執行次數
public void firstSortArray(int array[]) {
int temp = 0;
int count = 0;
for (int i = 0; i < array.length - 1; i++) {
for (int j = 0; j < array.length - i - 1; j++) {
count++;
if (array[j] > array[j + 1]) {
temp = array[j];
array[j] = array[j + 1];
array[j + 1] = temp;
}
}
}
System.out.println("執行次數:"+count);
}
另外兩個的代碼我就不貼了
對[ 2, 1, 3, 4, 5,6] 這個數組進行排序,得到結果分別爲:
執行次數:15
最終結果:123456
執行次數:9
最終結果:123456
執行次數:5
最終結果:123456
可以看到,效率差距還是很明顯的