计数排序(Count sort)
用待排序序列的记录作为计数数组的下标,统计每个记录的个数,然后依次输出计数数组的下标,
即可得到有序序列。
基本思路
- 初始化一个计数数组,数组大小为所有记录中最大的数
- 遍历待排序序列,按照一定规则将记录映射到计数数组的下标
- 存在对应记录则该位置下标+1
- 把计数数组直接覆盖到输出数组(节约空间)
代码实现
void CountSort(int a[],int n) {//待排序数组a,长度n
int tmp[10000];//临时辅助数组,根据待排序数组的最大元素设置大小
memset(tmp,0,sizeof(tmp));//初始化为0
for(int i=0; i<n; i++)
tmp[a[i]]++;
int index=0;
for(int i=0; i<10000; i++)//覆盖回原数组
if(tmp[i]!=0)
while(tmp[i]--)
a[index++]=i;
}
复杂度
时间复杂度:O(n + k),n是输入数组长度,k是最大的数的大小
空间复杂度:O(n + k),n是输入数组长度,k是最大的数的大小
特点
- 非比较的、稳定的、排序算法
- 快,线性时间复杂度,O(n)
- 局限性,需要一定辅助空间,牺牲空间换时间,适用于范围集中的数据
优化
思考
- 如果待排序记录中存在负数(无法实现)
- 如果待排序记录中最小为10000,最大为20000(存在较大的空间浪费)
解决(相对映射)
假设待排序记录中最小为10000,最大为20000,我们只需要10000个辅助空间即可(20000-10000),用0表示10000,10000表示20000。
void CountSort(int a[],int n) {
//找出最小、最大值,确定临时数组大小
int min_=a[0],max_=a[0];
for(int i=0;i<n;i++){
if(min_>a[i]) min_=a[i];
if(max_<a[i]) max_=a[i];
}
int tmp[max_-min_+1];//大小:最大值-最小值+1
memset(tmp,0,sizeof(tmp));//初始化为0
for(int i=0; i<n; i++)
tmp[a[i]-min_]++;//注意是相对映射(数据映射到下标时-min)
int index=0;
for(int i=0; i<=max_-min_; i++)//覆盖回原数组
if(tmp[i]!=0)
while(tmp[i]--)
a[index++]=i+min_;//恢复原数据需要+min
}