原理
计数排序是一个非基于比较的排序算法,该算法于1954年由
Harold H.
Seward提出。它的优势在于在对一定范围内的整数排序时,复杂度为O(n+k)(其中k是整数的范围),快于任何比较排序算法。计数排序的思想类似于哈希表中的直接定址法,在给定的一组序列中,先找出该序列中的最大值和最小值,从而确定需要开辟多大的辅助空间,每一个数在对应的辅助空间中都有唯一的下标。
它的大致流程如下:
一、开辟一个和原数组数值范围
一样大的空间,并记录原数组每个值的个数,类似于哈希的映射。
二、从头到尾遍历辅助空间的下标,如果它的数值不为0就将它次数个下标复制给原数组(因为下标代表原数组的值),又因为它是从头到尾遍历的,所以使用此种方法可以排序。
细节问题
首先这个方法到底要开多少内存呢?如果是按照数组最大值
来开辟空间无疑是浪费了大量的空间。
我们知道在使用这个数组的时候,我们只使用了它数组范围内的值来作为下标。
所以我们可以只用他范围内值作为空间,即开辟max - min + 1空间,此时我们再计数的时候就得这么计数tmp[arr[i]-min]++
,这么做它最小值对应的下标就是0,其他的数以此类推。
这么优化还有一个优点就是他可以处理负数
,例如:
原数组:-4,-9,3,2
最小值:-9
依次对应下标为:(-4-(-9))=5, (-9 - (-9)) = 0, (3-(-9))=12, 11
代码
void CountSort(int* arr, int n)
{
int mi = INT_MAX, mx = INT_MIN;
//找最大值和最小值
for (int i = 0; i < n; i++)
{
if(mi > arr[i])
mi = arr[i];
if(mx < arr[i])
mx = arr[i]
}
int range = mx - mi + 1;
int* tmp = (int*)calloc(range, sizeof(int));//开辟辅助空间
for (int i = 0; i < n; i++)
{
tmp[arr[i] - mi]++;
//计数
}
int j = 0;
//排序的过程
for (int i = 0; i < range; i++)
{
while (tmp[i] > 0)
{
arr[j++] = i + mi;
tmp[i]--;
}
}
}
总结:
- 计数排序是用空间换时间的算法
- 时间复杂度o(n), 空间复杂度o(n)
- 优点:效率极快
- 缺点:虽然可以处理负数,但无法处理小数,字符串,结构体…等多种类型,局限性大
感谢观众老爷的观看Thanks♪(・ω・)ノ,如果觉得满意的话留个关注再走吧。