非比较排序:计数排序和基数排序

计数排序
计数排序的基本思想:
给一个需要排序的数组,选出数组中的最大值和最小值确定这个数组的范围,新开辟一个这个范围大小的数组空间,这个临时数组中存储的是原来数组中各个元素出现的次数,最后再根据元素出现的次数将元素拷回原数组,此时,原数组有序。
这里写图片描述
代码实现:

//计数排序
void CountSort(int* a, int n)
{
    assert(a);
    int max = a[0];
    int min = a[0];
    for (int i = 0; i < n; ++i)
    {
        if (a[i] > max)
            max = a[i];
        if (a[i] < min)
            min = a[i];
    }
    int range = max - min + 1;
    int* tmp = new int[range];
    memset(tmp, 0, sizeof(int)* range);
    for (size_t i = 0; i < n; ++i)
    {
        tmp[a[i] - min]++;
    }
    int j = 0;
    for (int i = 0; i < range; ++i)
    {
        while (tmp[i]--)
        {
            a[j] = i + min;
            j++;
        }
    }
    delete[] tmp;
}

这里写图片描述
计数排序是一种非比较的排序方法,它的时间复杂度是O(N+K),空间复杂度是0(K),其中K是要排序的数组的范围。可以看出计数排序是一种以空间呢换取时间的方法。如果当K>N*logN的时候,计数排序就不是好的选择了,因为基于比较排序的算法的下限是O(N*logN)。所以计数排序比较适合数据范围集中的排序,且不能是字符串。

基数排序
基数排序的基本思想:
LSD– Least Significant Digit first(从低位向高位排)
MSD– Most Significant Digit first(从高位向低位排)
基数排序又称“桶子法”,是一种基于元素各个位上的数字进行的排序,先从个位开始,分别准备两个元素为0-9的桶子,第一个桶用来记录数组中各个元素个位上的数字在i(i = 0…..9)号位置出现的次数,第二个桶子用来记录该位置上对应的数据第一次出现的位置,然后以此类推往高位上走。这样的叙述似乎是有些难以理解,同样用图解释:
假设有如下数组,先对个位排序:
这里写图片描述
将对个位排完序的结果拷给原来的数组a,再对十位进行排序:
这里写图片描述
代码实现:

//基数排序
void LSDSort(int* a, int n)
{
    assert(a);
    //base总比digits多一个数量级
    int base = 10;
    int digits = 1;
    for (int i = 0; i < n; ++i)
    {
        while (a[i] >= base)
        {
            digits++;
            base *= 10;
        }
    }
    base = 1;
    //临时数组
    int* buckets = new int[n];
    for (int j = 0; j < digits; ++j)
    {
        //第一个桶
        int count[10] = { 0 };
        for (size_t i = 0; i < n; ++i)
        {
            int num = (a[i] / base) % 10;
            count[num]++;
        }
        //第二个桶
        int start[10] = { 0 };
        for (int i = 1; i <= 10; ++i)
        {
            start[i] = start[i - 1] + count[i - 1];
        }
        //排序
        for (int i = 0; i < n; ++i)
        {
            int num = (a[i] / base) % 10;
            int index = start[num]++;
            buckets[index] = a[i];
        }
        //拷回a
        memcpy(a, buckets, sizeof(int)*n);
        base *= 10;
    }
    delete[]buckets;
}

这里写图片描述
基数排序是一种非比较排序,它的时间复杂度是O(N*digit),其中digit是这组待排序中的最大的数的数量级。基数排序的空间复杂度就是在分配元素时,使用的桶空间,所以基数排序的空间复杂度是O(N)。它是一种稳定的排序方法。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值