基数排序

基数排序(桶排序)
基本思想:
    是将阵列分别有限数量的桶子里。每个桶子再个别排序。桶排序是鸽巢排序的一种归纳结果。当要
被排序的数值是均匀分配的时候,桶排序使用线性时间(O(n));
桶排序的缺点:
    1)首先是空间复杂度比较高,需要额外开销大。排序有两个数组空间开销,一个存放待排序数组,
一个就是所谓的桶,比如待排序值是从0到m-1,那就需要m个桶,这个桶组就要至少m个空间。
    2)其次待排序的元素都要在一定范围内等等
        桶式排序是一种分配排序。分配排序的特定是不需要进行关键码的比较,单前提是要知道待排序
    序列的一些具体情况。
MSD:
#include<stdio.h>
#include<stdlib.h>

int getdigit(int x,int d)
{
    int a[] = {1,1,10};   //因为待排序最大数据也只有两位数,所以在此只需要到十位就满足
    return ((x/a[d])%10);  //确定桶号
}

void PrintArr(int ar[], int n)
{
    int i;
    for(i=0;i<n; ++i)
        printf("%d ",ar[i]);
    printf("\n");
}
void msdradix_sort(int arr[],int begin,int end,int d)
{
    const int radix = 10;
    int count[radix] , i, j;
    //置空
    for(i=0; i<radix; ++i)
    {
        count[i] = 0;
    }
    //分配桶存储空间
    int *bucket = NULL;
    bucket = (int*)malloc((end-begin +1)*sizeof(int));
    if(bucket == NULL)
        printf("error!\n");
    //统计各桶需要装的元素的个数
    for(i=begin; i<=end; ++i)
    {
        int dd = getdigit(arr[i],d);
        count[dd]++;
    }
    //求出桶的边界索引,count[i]值为第i个桶的右边界索引+1
    for(i=1;i<radix; ++i)
    {
        count[i] = count[i] + count[i-1];
    }
    //这里要从右向左扫描,保证排序稳定性
    for(i = end; i>=begin; --i)
    {
        j = getdigit(arr[i],d);//求出关键码的第d位的数字, 例如:576的第3位是5
        bucket[count[j]-1] = arr[i];//放入对应的桶中,count[j]-1是第j个桶的右边界索引
        --count[j];//第j个桶放下一个元素的位置(右边界索引+1)
    }
    //注意:此时count[i]为第i个桶左边界
    //从各个桶中收集数据
    for(i = begin,j=0;i<=end; ++i,++j)
    {
        arr[i] = bucket[j];
    }
    //释放存储空间
    free(bucket);
    bucket = NULL;
    //堆各桶中数据进行再排序
    for(i=0;i<radix; i++)
    {
        int p1 = begin + count[i];     //第i个桶的左边界
        int p2 = begin + count[i+1] -1; //第i个桶的右边界
        if(p1<p2 && d > 1)
        {
            msdradix_sort(arr,p1,p2,d-1); //对第i个桶递归调用,进行基数排序,数位降1
        }
    }
}
int main()
{
    int ar[] = {12,14,54,5,6,3,9,8,47,89};
    int len = sizeof(ar)/sizeof(int);
    printf("sort befor:\n");
    PrintArr(ar,len);
    msdradix_sort(ar,0,len-1,2);
    printf("sort after : \n");
    PrintArr(ar,len);
    return 0;
}
LSD:
#include<stdio.h>
#include<stdlib.h>

#define MAXSIZE 10000

int getdigit(int x,int d)
{
    int a[] = {1,1,10,100};//最大三位数,所以这里只要百位就满足了
    return (x/a[d])%10;
}
void PrintArr(int ar[],int n)
{
    int i;
    for(i =0;i<n; ++i)
    {
        printf("%d ",ar[i]);
    }
    printf("\n");
}

void lsdradix_sort(int arr[],int begin,int end,int d)
{
    const int radix = 10;
    int count[radix],i,j;
    int *bucket = (int*)malloc((end - begin+1)*sizeof(int));//所有桶的空间开辟
    int k;
    //按照分配标准依次进行排序过程
    for(k=1;k<=d; ++k)
    {
        //置空
        for(i=0; i<radix; i++)
        {
            count[i] = 0;
        }
        //统计各个桶中所有数据个数
        for(i=begin; i<=end; i++)
        {
            count[getdigit(arr[i],k)]++;
        }
        //count[i]表示第i个桶的右边界索引
        for(i=1; i<radix; i++)
        {
            count[i] = count[i] + count[i-1];
        }
        //把数据依次装入桶(注意装入时候的分配技巧)
        for(i = end; i>=begin; --i) //这里要从右向左扫描,保证排序稳定性
        {
            j = getdigit(arr[i],k);//求出关键码的第k位的数字,例如:576的第3位是5
            bucket[count[j]-1] = arr[i];//放入对应的桶中,count[j]-1是j个桶的右边界索引
            --count[j];//对应桶的装入数据索引减一
        }
        //注意:此时 count[i]为i个桶左边界
        // 从各个桶中收集数据
        for(i= begin,j=0;i<=end;++i,++j)
        {
            arr[i] = bucket[j];
        }
    }
    free(bucket);
    bucket = NULL;
}
int main()
{
    int br[10] = {20,80,90,589,998,985,852,123,456,789};
    printf("sort befor:\n");
    PrintArr(br,10);
    lsdradix_sort(br,0,9,3);
    printf("sort after:\n");
    PrintArr(br,10);
    return 0;
}

posted @ 2018-05-31 10:55  努力飞的小菜鸟  阅读(209)  评论(0编辑  收藏  举报