計數排序、桶排序和基數排序

最近面試了一些人,發現你們都忽略了排序算法中的計數排序、桶排序和基數排序,segmentfault中都沒有它們的標籤就是一明證,呵呵!面試

計數排序

當輸入的元素是 n 個 0 到 k 之間的整數時,它的運行時間是 Θ(n + k)。計數排序不是比較排序,排序的速度快於任何比較排序算法。算法

因爲用來計數的數組C的長度取決於待排序數組中數據的範圍(等於待排序數組的最大值與最小值的差加上1),這使得計數排序對於數據範圍很大的數組,須要大量內存。計數排序是用來排序0到100之間的數字的最好的算法,可是它不適合按字母順序排序人名。可是,計數排序能夠用在基數排序中的算法來排序數據範圍很大的數組。segmentfault

算法的步驟以下:數組

  1. 找出待排序的數組中最大和最小的元素
  2. 統計數組中每一個值爲i的元素出現的次數,存入數組C的第i項
  3. 對全部的計數累加(從C中的第一個元素開始,每一項和前一項相加)
  4. 反向填充目標數組:將每一個元素i放在新數組的第C(i)項,每放一個元素就將C(i)減去1
#define NUM_RANGE (100)    //預約義數據範圍上限,即K的值

void counting_sort(int *ini_arr, int *sorted_arr, int n)  //所需空間爲 2*n+k
{  
       int *count_arr = (int *)malloc(sizeof(int) * NUM_RANGE);  
       int i, j, k;  

       //初始化統計數組元素爲值爲零 
       for(k=0; k<NUM_RANGE; k++){  
               count_arr[k] = 0;  
       }  
       //統計數組中,每一個元素出現的次數    
       for(i=0; i<n; i++){  
               count_arr[ini_arr[i]]++;  
       }  

       //統計數組計數,每項存前N項和,這實質爲排序過程
       for(k=1; k<NUM_RANGE; k++){  
               count_arr[k] += count_arr[k-1];  
       }  

       //將計數排序結果轉化爲數組元素的真實排序結果
       for(j=n-1 ; j>=0; j--){  
           int elem = ini_arr[j];          //取待排序元素
           int index = count_arr[elem]-1;  //待排序元素在有序數組中的序號
           sorted_arr[index] = elem;       //將待排序元素存入結果數組中
           count_arr[elem]--;              //修正排序結果,實際上是針對算得元素的修正
       }  
       free(count_arr);  
}

桶排序

個人理解:性能

桶排序是計數排序的變種,把計數排序中相鄰的m個"小桶"放到一個"大桶"中,在分完桶後,對每一個桶進行排序(通常用快排),而後合併成最後的結果。code

基本思想:排序

桶排序假設序列由一個隨機過程產生,該過程將元素均勻而獨立地分佈在區間[0,1)上。咱們把區間[0,1)劃分紅n個相同大小的子區間,稱爲桶。將n個記錄分佈到各個桶中去。若是有多於一個記錄分到同一個桶中,須要進行桶內排序。最後依次把各個桶中的記錄列出來記獲得有序序列。內存

效率分析:效率

桶排序的平均時間複雜度爲線性的O(N+C),其中C爲桶內快排的時間複雜度。若是相對於一樣的N,桶數量M越大,其效率越高,最好的時間複雜度達到O(N)。 固然桶排序的空間複雜度 爲O(N+M),若是輸入數據很是龐大,而桶的數量也很是多,則空間代價無疑是昂貴的。此外,桶排序是穩定的。統計

基數排序

基本思想:

將待排數據中的每組關鍵字依次進行桶分配。

具體示例:

27八、10九、06三、930、58九、18四、50五、26九、00八、083

咱們將每一個數值的個位,十位,百位分紅三個關鍵字: 278 -> k1(個位)=8,k2(十位)=7,k3=(百位)=2。

而後從最低位個位開始(從最次關鍵字開始),對全部數據的k1關鍵字進行桶分配(由於,每一個數字都是 0-9的,所以桶大小爲10),再依次輸出桶中的數據獲得下面的序列。

930、06三、08三、18四、50五、27八、00八、10九、58九、269

再對上面的序列接着進行鍼對k2的桶分配,輸出序列爲:

50五、00八、10九、930、06三、26九、27八、08三、18四、589

最後針對k3的桶分配,輸出序列爲:

00八、06三、08三、10九、18四、26九、27八、50五、58九、930

效率分析:

基數排序的性能比桶排序要略差。每一次關鍵字的桶分配都須要O(N)的時間複雜度,並且分配以後獲得新的關鍵字序列又須要O(N)的時間複雜度。假如待排數據能夠分爲d個關鍵字,則基數排序的時間複雜度將是O(d*2N) ,固然d要遠遠小於N,所以基本上仍是線性級別的。基數排序的空間複雜度爲O(N+M),其中M爲桶的數量。通常來講N>>M,所以額外空間須要大概N個左右。

可是,對比桶排序,基數排序每次須要的桶的數量並很少。並且基數排序幾乎不須要任何「比較」操做,而桶排序在桶相對較少的狀況下,桶內多個數據必須進行基於比較操做的排序。所以,在實際應用中,基數排序的應用範圍更加普遍。

相關文章
相關標籤/搜索