1. 程式人生 > >排序演算法(六)非比較排序----計數排序和基數排序

排序演算法(六)非比較排序----計數排序和基數排序

前邊的幾篇文章介紹的幾種排序演算法都是比較排序,接下來的文章將會介紹兩種非比較排序。 計數排序:

計數排序通過雜湊的方法將一組資料對映到一個數組裡,最後將陣列中的數依次讀取,並寫進原來的陣列,讀出的資料就是有序的。

綜合以上圖片的分析,我們知道,儲存資料資訊的陣列(即就是計數的count陣列)的大小應該是最大數與最小數之差再加1. 下邊請看程式碼實現:
//計數排序
void CountSort(int a[],int n)
{
    assert(a);
    //找到陣列中的最大元素和最小元素
    int min = a[0];
    int max = a[0];
    for(int i = 1; i < n; ++i)
    {
        if(a[i] > max)
            max = a[i];
        if(a[i] < min)
            min = a[i];
    }
    int range = max - min + 1;

    //開闢range大的count陣列
    int* count = new int[range];
    memset(count,0,sizeof(int) * range);

    //寫count陣列
    for(int i = 0; i < n; ++i)
    {
        count[a[i] - min]++;
    }

    //讀count陣列,並寫a陣列
    int index = 0;
    for(int i = 0; i < range; ++i)
    {
        while(count[i]--)
        {
            a[index++] = i + min;
        }
    }
}
計數排序,是比較快的排序,但是它卻有一定的缺陷。如果資料過於分散,計數排序的空間複雜度是比較高的(count陣列比較大)。如果資料很集中,計數排序就是比較快的。 基數排序 : 對一組資料進行排序,先按照其個位進行排序,然後按照十位進行排序,依次類推。

下邊給出程式碼實現:

//求最大數的位數
int GetMaxDigit(int a[],int n)
{
    int base = 10;
    int digit = 1;
    int i = 0;
    for(int i = 0; i< n ; ++i)
    {
       while(a[i] >= base)
       {
           digit ++;
           base *= 10;
       }
    }
    return digit;
}
//基數排序
void LSDSort(int a[],int n)
{
    assert(a);
    int digit = GetMaxDigit(a,n);
    int base = 1;
    //定義一個count陣列
    int count[10] = {0};
    int start[10] = {0};
    int* tmp = new int[n];
    while(digit--)
    {
       memset(count,0,sizeof(int) * 10);
       start[0] = 0;
       //寫count陣列
       for(int i = 0; i < n; ++i)
       {
           count[(a[i]/base) % 10]++;
       }
       //寫start陣列
       for(int i = 1; i < 10; ++i)
       {
           start[i] = start[i - 1] + count[i - 1];
       }
       //讀a陣列,寫tmp數
       int num = 0;
       for(int i = 0; i < n; ++i)
       {
           num = (a[i]/base) % 10;
           tmp[start[num]] = a[i];
           start[num]++;
       }
       //將tmp陣列寫回a陣列
       for(int i = 0; i < n; ++i)
       {
           a[i] = tmp[i];
       }
       base *= 10;
    }
    delete[] tmp;
}

根據上圖的分析,需要按照最大的數的每個位都進行排序之後,整個陣列才會有序。 基數排序的缺陷:適用於資料比較集中的情況,不能對負數進行排序。 如果對以上的  求最大數的位數  的那種辦法不能理解,你可以採用一種理解起來比較簡單但是稍微麻煩的辦法:找出最大的數,然後求出他的位數。