排序和查找-计数排序(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 
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;
}

你可能感兴趣的:(算法)