基数排序

基数排序(桶排序)

基数排序(Radix Sort)又称多关键码排序,它通过一些键值,将序列中的元素分配至相应的桶中,以达到排序的目的,它是一种稳定的排序算法,其时间复杂度为O(M*N),M为数据位数,N为数据个数,空间复杂度为O(N)。

基数排序又分为低关键码优先和高关键码优先两种。

我们先来研究第一种:

低关键码优先排序

步骤:
1.首先根据个位数的数值,将所有数据分配到0~9号桶中
2.再将所有桶中的数据按桶号由大到小依次重新收集起来
3.再将十位百位以及更高位按照同样的方式分配并收集

代码如下:

//获取一组序列中最大元素的位数
int GetBitNum(int array[], int size)
{
    int i = 0;
    int count = 0;
    int max = array[0];
    for (i=1; i < size; ++i)
    {
        if (array[i]>max)
            max = array[i];
    }
    while (max)
    {
        count++;
        max /= 10;
    }
    return count;
}


void RadixSortLSD(int array[], int size)
{
    //开辟空间用来收集数据
    int *bucket = (int*)malloc(sizeof(array[0])*size);
    if (NULL == bucket)
        return;
    int i = 0;
    int bitNum = GetBitNum(array, size);
    int bitidx = 0;
    int radix = 1;
    //循环最大元素的位数次
    for (; bitidx < bitNum; ++bitidx)
    {
        //统计每个桶中的元素个数
        int count[10] = { 0 };
        int startAddr[10] = { 0 };
        for (i=0; i < size; ++i)
        {
            count[array[i]/radix % 10]++;
        }
        //计算每个桶的起始位置
        for (i = 1; i < 10; ++i)
        {
            startAddr[i] = startAddr[i - 1] + count[i - 1];
        }
        //将元素放入对应桶中
        for (i = 0; i < size; ++i)
        {
            int bucketNo = array[i] / radix % 10;
            bucket[startAddr[bucketNo]++] = array[i];
        }
        //对元素进行回收
        memcpy(array, bucket, sizeof(array[0])*size);

        radix *= 10;
    }
}

测试用例:

int main()
{
    int array[] = { 203,156,369,420,671,523,188,198,453,120,479 };
    PrintArray(array, sizeof(array) / sizeof(array[0]));
    RadixSortLSD(array, sizeof(array) / sizeof(array[0]));
    PrintArray(array, sizeof(array) / sizeof(array[0]));
}

运行结果:

这里写图片描述


接下来看第二种

高关键码优先

与低关键码优先方法类似,但是必须用递归实现
先将高位按照以上方式进行归位,再将每个桶中的元素按照次高位由大到小进行归位,以此类推直至最低位

代码如下:

void _RadixSortMSD(int array[], int left, int right,int *bucket, int bit)
{
    if (bit < 0)
        return;

    int radix = pow((double)10, bit);//求x的y次方
    int count[10] = { 0 };
    int startAddr[10] = { 0 };
    int i = 0;
    //计算每个桶中有效元素的个数
    for (i = left; i < right; ++i)
    {
        count[array[i] / radix%10]++;
    }
    //求每个桶的起始位置
    for (i = 1; i < 10; ++i)
    {
        startAddr[i] = startAddr[i - 1] + count[i - 1];
    }
    //将元素们放入桶中对应位置
    for (i = left; i < right; ++i)
    {
        int bucketNo = array[i] / radix%10;
        bucket[startAddr[bucketNo]++] = array[i];
    }
    //回收桶中元素
    memcpy(array + left, bucket, sizeof(array[0])*(right - left));

    //再将每个桶中的元素作为一个序列进行桶排序
    for (i = 0; i < 10; ++i)
    {
        int begin = startAddr[i] - count[i];
        int end = startAddr[i];
        _RadixSortMSD(array, begin, end, bucket, bit - 1);
    }
}


void RadixSortMSD(int array[], int size)
{
    int *bucket = (int *)malloc(sizeof(array[0])*size);
    if (NULL == bucket)
        return;
    _RadixSortMSD(array, 0, size,bucket, GetBitNum(array, size) - 1);
    free(bucket);
}

测试用例:

int main()
{
    int array[] = { 203,156,369,420,671,523,188,198,453,120,479 };
    PrintArray(array, sizeof(array) / sizeof(array[0]));
    RadixSortMSD(array, sizeof(array) / sizeof(array[0]));
    PrintArray(array, sizeof(array) / sizeof(array[0]));
}

运行结果:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值