氣泡排序就這麼簡單
在我大一的時候自學c語言和資料結構,我當時就接觸到了氣泡排序(當時使用的是C語言編寫的)。現在大三了,想要在暑假找到一份實習的工作,又要回顧一下資料結構與演算法的知識點了。
排序對我們來說是一點也不陌生了,當你打王者榮耀的時候也會有段位之分,當你打Dota的時候也有天梯分。從高往下數,這個排名是有規律的,就是一種排序。
我最開始接觸的就是氣泡排序,所以這篇博文主要講的是氣泡排序。
氣泡排序的實現
來源百度百科:
氣泡排序(Bubble Sort,臺灣譯為:泡沫排序或氣泡排序)是一種簡單的排序演算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個演算法的名字由來是因為越大的元素會經由交換慢慢“浮”到數列的頂端,故名。
演算法描述:
i
從0開始,i
與i+1
比較,如果i>i+1
,那麼就互換i
不斷增加,直到i<n-1
(n是陣列元素的個數,n-1
是陣列已經最後一個元素) ,一趟下來,可以讓陣列元素中最大值排在陣列的最後面
從最簡單開始,首先我們建立一個陣列,該陣列有5位數字:
int[] arrays = {2, 5, 1, 3, 4};
複製程式碼
一、第一趟排序
下面我們根據演算法的描述來進行程式碼驗算**(第一趟排序)**:
//使用臨時變數,讓兩個數互換
int temp;
//第一位和第二位比
if (arrays[0] > arrays[1]) {
//交換
temp = arrays[0];
arrays[0] = arrays[1];
arrays[1] = temp;
}
//第二位和第三位比
if (arrays[1] > arrays[2]) {
temp = arrays[1];
arrays[1] = arrays[2];
arrays[2] = temp;
}
//第三位和第四位比
if (arrays[2] > arrays[3]) {
temp = arrays[2];
arrays[2] = arrays[3];
arrays[3] = temp;
}
//第四位和第五位比
if (arrays[3] > arrays[4]) {
temp = arrays[3];
arrays[3] = arrays[4];
arrays[4] = temp;
}
複製程式碼
如果前一位的數比後一位的數要大,那麼就交換,直到將陣列的所有元素都比較了一遍!
經過我們第一趟比較,我們可以發現:最大的值就在陣列的末尾了!
一、第二趟排序
第二趟排序跟第一趟排序一樣,也是用前一位與後一位比較,如果前一位比後一位要大,那就交換。值得注意的是:並不需要與最後一位比較了,因為在第一趟排序完了,最後一位已經是最大的數了。同理,我們第二趟排序完了之後,倒數第二位也是第二大的數了。
第二趟排序的程式碼如下:
//第一位和第二位比
if (arrays[0] > arrays[1]) {
//交換
temp = arrays[0];
arrays[0] = arrays[1];
arrays[1] = temp;
}
//第二位和第三位比
if (arrays[1] > arrays[2]) {
temp = arrays[1];
arrays[1] = arrays[2];
arrays[2] = temp;
}
//第三位和第四位比
if (arrays[2] > arrays[3]) {
temp = arrays[2];
arrays[2] = arrays[3];
arrays[3] = temp;
}
//第四位不需要和第五位比了,因為在第一趟排序結束後,第五位是最大的了。
複製程式碼
結果:我們的第二大數已經排在了倒數第二位了
三、程式碼簡化
值得說明的是:上面的結果看起來已經是排序好的了,其實是我在測試時資料還不足夠亂,如果資料足夠亂的話,是需要4(n-1)趟排序的!
但我們從上面的程式碼就可以發現:第一趟和第二趟的比較、交換程式碼都是重複的,並且我們的比較都是寫死的(0,1,2,3,4),並不通用!
我們的陣列有5位數字
- 第一趟需要比較4次
- 第二趟需要比較3次
我們可以根據上面規律推斷出:
- 第三趟需要比較2次
- 第四躺需要比較1次
再從上面的規律可以總結出:5位數的陣列需要4躺排序的,每躺排序之後次數減1(因為前一趟已經把前一趟數的最大值確定下來了)!
於是我們可以根據for迴圈和變數將上面的程式碼進行簡化:
int temp;
//外層迴圈是排序的趟數
for (int i = 0; i < arrays.length - 1 ; i++) {
//內層迴圈是當前趟數需要比較的次數
for (int j = 0; j < arrays.length - i - 1; j++) {
//前一位與後一位與前一位比較,如果前一位比後一位要大,那麼交換
if (arrays[j] > arrays[j + 1]) {
temp = arrays[j];
arrays[j] = arrays[j + 1];
arrays[j + 1] = temp;
}
}
}
複製程式碼
四、氣泡排序優化
從上面的例子我們可以看出來,如果資料足夠亂的情況下是需要經過4躺比較才能將陣列完整排好序。但是我們在第二躺比較後就已經得到排好序的陣列了。
但是,我們的程式在第二趟排序後仍會執行第三趟、第四趟排序。這是沒有必要的,因此我們可以對其進行優化一下:
- 如果在某躺排序中沒有發生交換位置,那麼我們可以認為該陣列已經排好序了。
- 這也不難理解,因為我們每趟排序的目的就是將當前趟最大的數置換到對應的位置上,沒有發生置換說明就已經排好序了。
程式碼如下:
//裝載臨時變數
int temp;
//記錄是否發生了置換, 0 表示沒有發生置換、 1 表示發生了置換
int isChange;
//外層迴圈是排序的趟數
for (int i = 0; i < arrays.length - 1; i++) {
//每比較一趟就重新初始化為0
isChange = 0;
//內層迴圈是當前趟數需要比較的次數
for (int j = 0; j < arrays.length - i - 1; j++) {
//前一位與後一位與前一位比較,如果前一位比後一位要大,那麼交換
if (arrays[j] > arrays[j + 1]) {
temp = arrays[j];
arrays[j] = arrays[j + 1];
arrays[j + 1] = temp;
//如果進到這裡面了,說明發生置換了
isChange = 1;
}
}
//如果比較完一趟沒有發生置換,那麼說明已經排好序了,不需要再執行下去了
if (isChange == 0) {
break;
}
}
複製程式碼
五、擴充套件閱讀
C語言實現第一種方式:
void bubble ( int arr[], int n)
{
int i;
int temp;
for (i = 0; i < n - 1; i++) {
if (arr[i] > arr[i + 1]) {
temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
void bubbleSort ( int arr[], int n)
{
int i;
for (i = n; i >= 1; i--) {
bubble(arr, i);
}
}
複製程式碼
C語言實現第二種方式遞迴:
void bubble ( int arr[], int L, int R)
{
if (L == R) ;
else {
int i;
for (i = L; i <= R - 1; i++)//i只能到達R-1
if (arr[i] > arr[i + 1]) {
int temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
bubble(arr, L, R - 1);//第一輪已排好R
}
}
複製程式碼
測試程式碼:
int main ()
{
int arr[] = {2, 3, 4, 511, 66, 777, 444, 555, 9999};
bubbleSort(arr, 8);
for (int i = 0; i < 9; i++)
cout << arr[i] << endl;
return 0;
}
複製程式碼
5.1時間複雜度的理解:
如果文章有錯的地方歡迎指正,大家互相交流。習慣在微信看技術文章,想要獲取更多的Java資源的同學,可以關注微信公眾號:Java3y