計數排序,基數排序,桶排序

參考:https://blog.csdn.net/sinat_34820292/article/details/82861535?depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1

參考:https://blog.csdn.net/taotaofu/article/details/69062323?utm_source=copy  幫助理解

https://blog.csdn.net/yushiyi6453/article/details/76407640

O(n)的排序算法

計數排序,基數排序,桶排序

之所以它們的時間複雜度能到達O(n),是因爲它們都是非基於比較的排序算法,不涉及元素之間的比較操作。

 

一 計數排序(Counting Sort)

計數排序的基本思想就是對每一個輸入元素x,確定小於x的元素的個數,這樣就可以把x直接放在它在最終輸出數組的位置上,例如:

算法的步驟大致如下:

  • 找出待排序的數組中最大和最小的元素

  • 統計數組中每個值爲i的元素出現的次數,存入數組C的第i項

  • 對所有的計數累加(從C中的第一個元素開始,每一項和前一項相加)

  • 反向填充目標數組:將每個元素i放在新數組的第C(i)項,每放一個元素就將C(i)減去1

當輸入的元素是0到k之間的整數時,時間複雜度是O(n+k),空間複雜度也是O(n+k)。當k不是很大並且序列比較集中時,計數排序是一個很有效的排序算法。計數排序是一個穩定的排序算法。

二 基數排序(Radix Sort)

基數排序(Radix Sort)是一種非比較型排序算法,它將整數按位數切割成不同的數字,然後按每個位分別進行排序。基數排序的方式可以採用MSD(Most significant digital)或LSD(Least significant digital),MSD是從最高有效位開始排序,而LSD是從最低有效位開始排序。

當然我們可以採用MSD方式排序,按最高有效位進行排序,將最高有效位相同的放到一堆,然後再按下一個有效位對每個堆中的數遞歸地排序,最後再將結果合併起來。但是,這樣會產生很多中間堆。所以,通常基數排序採用的是LSD方式
LSD基數排序實現的基本思路是將所有待比較數值(正整數)統一爲同樣的數位長度,數位較短的數前面補零。然後,從最低位開始,依次進行一次排序。這樣從最低位排序一直到最高位排序完成以後, 數列就變成一個有序序列。需要注意的是,對每一個數位進行排序的算法必須是穩定的,否則就會取消前一次排序的結果。通常我們使用計數排序或者桶排序作爲基數排序的輔助算法。可以查看基數排序的動畫來幫助理解,動畫中的每一輪排序實際上是二中的計數排序,計數排序沒理解也可以參考這個動畫理解。

如下圖的基數排序的例子,採用LSD策略,把三位數字的三個數位作爲三個排序的參數,實際問題中可能是三個不相關的具有不同排序地位的屬性,如sql中:ORDER BY age DESC , weight DESC , score ASC (當然,SQL中的排序是LSD還是MSD的不得而知)
在這裏插入圖片描述

基數排序的時間複雜度是 O(k·n),其中n是排序元素個數,k是數字位數。注意這不是說這個時間複雜度一定優於O(nlgn),因爲n可能具有比較大的係數k。

三 桶排序

桶排序(Bucket Sort)的思想是將數組分到有限數量的桶子裏。每個桶子再個別排序(有可能再使用別的排序算法)。當要被排序的數組內的數值是均勻分配的時候,桶排序可以以線性時間運行。桶排序過程動畫演示:Bucket Sort,桶排序原理圖如下:

實現代碼:

/*算法:桶排序*/
 
#include <iostream>
#include <vector>
#include <algorithm>
 
using namespace std;
 
void bksort(float A[],int l,int h){
    int size = h-l+1;
    vector<float> b[size];//有size個數據,就分配size個桶
    for(int i=l;i<=h;i++){
        int bi = size*A[i];//元素A[i]的桶編號
        b[bi].push_back(A[i]);//將元素A[i]壓入桶中
    }
    for(int i=0;i<size;i++)
        sort(b[i].begin(),b[i].end());//桶內排序
    int idx = l;//指向數組A的下標
    for(int i=0;i<size;i++){//遍歷桶
        for(int j=0;j<b[i].size();j++){//遍歷桶內元素
            A[idx++] = b[i][j];
        }
    }
}
 
int main(){
    float A[] = {0.78,0.17,0.39,0.26,0.72,0.94,0.21,0.12,0.23,0.68};
    bksort(A,2,9);
    for(int i=0;i<10;i++)
        cout<<A[i]<<" ";
}
/*https://www.cnblogs.com/skywang12345/p/3602737.html
 * 桶排序
 *
 * 參數說明:
 *     a -- 待排序數組
 *     n -- 數組a的長度
 *     max -- 數組a中最大值的範圍
 */
void bucketSort(int a[], int n, int max)
{
    int i,j;
    int buckets[max];

    // 將buckets中的所有數據都初始化爲0。
    memset(buckets, 0, max*sizeof(int));

    // 1. 計數
    for(i = 0; i < n; i++) 
        buckets[a[i]]++; 

    // 2. 排序
    for (i = 0, j = 0; i < max; i++) 
    {
        while( (buckets[i]--) >0 )
            a[j++] = i;
    }
}

參數模板:https://blog.csdn.net/chuanzhouxiao/article/details/89080489

四 三種排序時間複雜度及應用場景

https://www.cnblogs.com/zpchya/p/10801324.html

 

 

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