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

来源:互联网 发布:自定义端口号范围 编辑:程序博客网 时间:2024/06/06 04:24

转载自基数排序(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
原创粉丝点击