冒泡排序(Bubble Sort),是一種計算機科學領域的較簡單的排序算法。它重複地走訪過要排序的數列,一次比較兩個元素,如果他們的順序錯誤就把他們交換過來。走訪數列的工作是重複地進行直到沒有再需要交換,也就是說該數列已經排序完成。這個算法的名字由來是因爲越大的元素會經由交換慢慢“浮”到數列的頂端,故名。
算法分析
冒泡排序算法是所有排序算法中最簡單的(前面也提到過),在生活中應該也會看到氣泡從水裏面出來時,越到水面上氣泡就會變的越大。在物理上學氣壓的時候好像也看到過這種現象;其實理解冒泡排序就可以根據這種現象來理解:每一次遍歷,都把大的往後面排(當然也可以把小的往後面排),所以每一次都可以把無序中最大的(最小)的元素放到無序的最後面(或者說有序元素的最開始);
基本步驟:
1、外循環是遍歷每個元素,每次都放置好一個元素;
2、內循環是比較相鄰的兩個元素,把大的元素交換到後面;
3、等到第一步中循環好了以後也就說明全部元素排序好了;
代碼實現
#include<stdio.h>
//打印數組元素
void print_array(int *array, int length)
{
int index = 0;
printf("array:\n");
for(; index < length; index++){
printf(" %d,", *(array+index));
}
printf("\n\n");
}
void bubbleSort(int array[], int length)
{
int i, j, tmp;
if (1 >= length) return;// 判斷參數條件
for (i = length-1; i > 0; i--){//外循環,循環每個元素
for (j = 0; j < i; j++){ // 內循環,
if (array[j] > array[j+1]){// 交換相鄰的兩個元素
tmp = array[j];
array[j] = array[j+1];
array[j+1] = tmp;
}
}
}
}
int main(void)
{
int array[12] = {1,11,12,4,2,6,9,0,3,7,8,2};
print_array(array, 12);
bubbleSort(array, 12);
print_array(array, 12);
return 0;
}
運行結果:
時間複雜度
這個時間複雜度還是很好計算的:外循環和內循環以及判斷和交換元素的時間開銷;
最優的情況也就是開始就已經排序好序了,那麼就可以不用交換元素了,則時間花銷爲:[ n(n-1) ] / 2;所以最優的情況時間複雜度爲:O( n^2 );
最差的情況也就是開始的時候元素是逆序的,那麼每一次排序都要交換兩個元素,則時間花銷爲:[ 3n(n-1) ] / 2;(其中比上面最優的情況所花的時間就是在於交換元素的三個步驟);所以最差的情況下時間複雜度爲:O( n^2 );
綜上所述:
最優的時間複雜度爲:O( n^2 ) ;有的說 O(n),下面會分析這種情況;
最差的時間複雜度爲:O( n^2 );
平均的時間複雜度爲:O( n^2 );
空間複雜度
空間複雜度就是在交換元素時那個臨時變量所佔的內存空間;
最優的空間複雜度就是開始元素順序已經排好了,則空間複雜度爲:0;
最差的空間複雜度就是開始元素逆序排序了,則空間複雜度爲:O(n);
平均的空間複雜度爲:O(1);
最優時間複雜度 n
有很多人說冒泡排序的最優的時間複雜度爲:O(n);其實這是在代碼中使用一個標誌位來判斷是否已經排序好的,修改下上面的排序代碼:
void bubbleSort(int array[], int length)
{
int i, j, tmp;
int flag = 1;
if (1 >= length) return;
for (i = length-1; i > 0; i--, flag = 1){
for (j = 0; j < i; j++){
if (array[j] > array[j+1]){
tmp = array[j];
array[j] = array[j+1];
array[j+1] = tmp;
flag = 0;
}
}
if (flag) break;
}
}
根據上面的代碼可以看出,如果元素已經排序好,那麼循環一次就直接退出。或者說元素開始就已經大概有序了,那麼這種方法就可以很好減少排序的次數;其實我感覺這種方法也有弊端,比如 要額外的判斷下,以及賦值操作;
空間複雜度爲 0
有人會說這個空間複雜度能降到0,因爲空間複雜度主要是看使用的輔助內存,如果沒有輔助內存變量,那麼可以說空間複雜度爲0;所以該算法中空間複雜度一般是看交換元素時所使用的輔助空間;
1、 a = a + b; b = a - b; a = a - b;
2、 a = a * b; b = a / b; a = a / b;
3、 a = a ^ b; b = a ^ b;a = a ^ b;
上面幾種方法都可以不使用臨時空間來交換兩個元素,但是都有些潛在的問題,比如 越界;所以個人覺得還是老老實實的用個臨時變量吧,這樣算法意圖就比較清晰了。