排序和查找-计数排序(Counting Sort)

转载自基数排序(Radix Sorting)

0 前言

常见的非比较排序算法:计数排序,基数排序,桶排序;平均时间复杂度都是O(n),但是限制比较多

比较算法的时间复杂度下限为O(nlogn)

1 思路

输入的元素使n个0到k之间的整数时,时间复杂度为 Θn+k

由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组需要大量时间和内存。但计数排序可用于在基数排序算法中,来排序数据范围很大的数组。

通俗理解:10个年龄不同的人,统计出8个人的年龄比A小,那么A的年龄排在第9位。年龄重复时,需要特殊处理(保证稳定性),所以最后要反向填充目标数组,以及将每个数字的统计减去1。

算法步骤如下:

  1. 找出待排序的数组中的最大和最小的元素
  2. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项
  3. 对所有的计数累加(从C中的第1个元素开始,每一项和前一项相加)
  4. 反向填充目标数组,将每个元素i放在新数组的第C(i)项,每放一个就将C(i)减去1

    假定输入时数组A[1..n], length(A)=n。 另外还需要一个存放排序结果的数组B[1..n],以及提供临时存储区的C[0..k] k是所有元素中最大的一个。

#include <iostream>
using namespace std;

int getMax(int arr[], const int size){
    int max = 0;
    for(int i = 0; i < size; ++i){
        if(arr[i] > max) max = arr[i];
    }
    return max;
}

void countingSort(int a[], int size_a, int b[], const int k){
    int* c = new int[k+1];

    for(int i = 0; i < k; ++i){
        c[i] = 0; // 初始化计数数组
    }

    for(int i = 0; i < size_a; ++i){
        c[a[i]]++; // 计数
    }

    for(int i = 1; i <= k; ++i){
        c[i] += c[i-1]; // 累加
    }

    for(int i = size_a - 1; i >= 0; --i){ // 反向填充
        b[c[a[i]] - 1] = a[i]; // 对应位置
        c[a[i]]--; // 填充完成一个删一个
    }

}

int main(){
    int a[] = {2,5,3,0,2,3,0,3};
    const int size_a = sizeof(a)/sizeof(int);
    int* b = new int[size_a];

    countingSort(a, size_a, b, getMax(a, size_a));
    for(int i = 0; i < size_a; ++i){
        cout << b[i] << " ";
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值