什么是计数排序
如上图,统计数组中值的个数:
2个[1]:1,1
1个[2]:2
3个[3]:3,3,3
2个[4]:4,4
传给原数组:(即完成排序↓)
1 | 1 | 2 | 3 | 3 | 3 | 4 | 4 |
---|
- Step1. 统计出每个数据出现的次数:计数数组,每个下标对应相应的值
- 映射:让具有统一特征的值到同一个位置去
- 绝对映射:上面👆那个例子就是绝对映射,数值为 1 就被统计到计数数组中下标为 [1] 的位置
- 相对映射:如下这个数组,数值的范围是:max-min → 1004-1000 = 4,由此创建大小为
sizeof(int)*4
的计数数组
- 映射:让具有统一特征的值到同一个位置去
1004 | 1000 | 1003 | 1000 | 1002 | 1003 | 1003 | 1004 |
---|
[0] | [1] | [2] | [3] |
---|---|---|---|
↓ | ↓ | ↓ | ↓ |
min | min+1 | min+2 | max |
- Step2. 将计数数组中统计的结果写入原数组
- ps.开辟计数数组的空间用
calloc
(因为需要初始化计数数组)❗记得最后要free
代码
// 计数排序
void CountSort(int* a, int n)
{
assert(a);
int min = a[0], max = a[0];
for (size_t i = 0; i < n; i++)
{
if (a[i] > max)
max = a[i];
if (a[i] < min)
min = a[i];
}
int size = max - min + 1;
int* tmp = (int*)calloc(size, sizeof(int));
if (!tmp)
{
perror("calloc fail");
exit(-1);
}
//计数
for (size_t i = 0; i < n; i++)
{
++tmp[*(a + i) - min];
}
int j = 0;
for (size_t i = 0; i < size; i++)
{
while (tmp[i]--)
{
a[j++] = i + min;
}
}
free(tmp);
tmp = NULL;
}
特性分析
range = max - min
-
时间复杂度:O(N+range)
-
空间复杂度:O(range)
-
缺点:不适合 range 很大的 → 适合范围集中的数据且只适合整型