目录
一 基本思想
①根据所给的数组确定范围
②开辟对应范围大小的一个数组,用来记录每一个数字出现的个数
③根据这个数组中的关系重新把数字放回原数组
给定一个数组,我们需要根据数组的范围确定对应的计数数组的大小。假设数组中最大数字和最小数字相差了多少,对应的我们的数组就开多大
所以首先我们需要找出最大的和最小的数字,再确定一个范围,用来开辟计数的数组的空间
,这个数组用来统计每一个数字在对应的位置出现了多少次,由于这一个数组下标是已经排好序的,因此我们之后取数据的时候根据数组的下标可以直接放回原来的数组。并且一个位置的数据有可能出现不止一次,我们要保证数据全部都出完
优化
由于计数排序需要额外的开辟空间,所以如果不利用范围进行优化的话,直接原数组有多大就开辟多大的数组,那么如果数组分散的比较开,就会有很多空间上的浪费。所以这里我们用的范围相当于一个相对大小的概念。比如如果数字是1001,1002,1008,1004,1007,我们就不需要开辟1008个空间,只用开辟8个空间,因为最小的1001和最大的1008之间差了8个数字,这几个数字肯定是分布在这个范围内的。
局限性:只适用于int类型的数据
二 图解
三 代码
void CountSort(int* a, int n)
{
assert(a);
int min = a[0];
int max = a[0];
for (int i = 0; i < n; i++)
{
if (a[i] < min)
{
min = a[i];
}
if(a[i]>max)
{
max = a[i];
}//用相对位置确定 找出最大值和最小值
}
int range = max - min + 1;
int* count = (int*)calloc(range,sizeof(int));
if (count == NULL)
{
printf("calloc fail!\n");
exit(-1);
}
for (int i = 0; i < n; i++)
{
count[a[i]-min]++;
}
int j = 0;
for (int i = 0; i < range; i++)
{
while (count[i]--)
{
a[j++] = i+min;
}
}
free(count);
count = NULL;
}
int main()
{
int ar[] = { 10,6,7,1,3,9,2,4 };
int sz = sizeof(ar) / sizeof(ar[0]);
printf("计数排序前:");
Print(ar, sz);
printf("\n");
CountSort(ar, sz);
printf("计数排序后:");
Print(ar, sz);
printf("\n");
}
四 总结:
局限性:数据类型和空间的额外消耗
时间复杂度O(N)
空间复杂度是O(N)
不同于八大经典排序,这是一种不依赖比较和交换的排序。