排序算法之 冒泡排序 及其時間複雜度和空間複雜度

        冒泡排序(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; 
      上面幾種方法都可以不使用臨時空間來交換兩個元素,但是都有些潛在的問題,比如 越界;所以個人覺得還是老老實實的用個臨時變量吧,這樣算法意圖就比較清晰了。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章