计数排序是一种不需要进行元素比较的算法,它是通过数组中元素出现的次数来确定其如何排列的。
以待排数组arr[] = {3,1,3,4,3,5,4,2}为例,对其计数排序的思路是这样的:
它需要创建两个临时空间,我们以tmp和count来表示,其中tmp临时存放已排好的数据。
count这个数组我们需要用两次,第一次存放待排数组arr各元素出现的次数,count[i]中存元素i出现的次数;第二次count[i]中存放小于等于i的元素的个数,其值可以用第一次存放的count[i] + count[i-1]得出。当然了,count里面的值最终是第二次的值。count的大小由待排数组的最大元素的值决定的。
然后开始从后往前依次取出待排数组arr中的元素,按照其在count中对应的值在临时数组tmp中对号入座 ,入座后该元素在count中的值应该减1,这样能保证arr中相同元素下一次进入tmp中能放在其前一个位置。
后面依次存放 ,直到遍历完arr中的元素。- 将tmp中的元素拷到arr中。
代码实现如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//参数分别为待排数组,待排数组的元素个数,和最大元素加1,失败返回0,成功返回1
int ctsort(int* arr,int sz,int k)
{
int *tmp = NULL;
int *count = NULL;
int i;
if(!(tmp=(int*)malloc(sz*sizeof(int)))) return 0;
if(!(count = (int*)malloc(k*sizeof(int)))) return 0;
for(i=0; i<k; i++)//将count各元素初始化为0
count[i] = 0;
for(i=0; i<sz; i++)//统计出各元素出现的次数并将其存放在count中
count[arr[i]] = count[arr[i]] + 1;
for(i=1; i<k; i++)//将小于等于各元素的数的个数存放在count中
count[i] = count[i]+count[i-1];
for(i=sz-1; i>=0; i--)//从后往前遍历arr,把其中的元素对号入座
{
tmp[count[arr[i]] - 1] = arr[i];
count[arr[i]] = count[arr[i]]-1;
}
memcpy(arr,tmp,sz*sizeof(int));//将tmp中的元素拷回arr
free(tmp);
free(count);
return 1;
}
int main()
{
int i;
int arr[] = {3,1,3,4,3,5,4,2};
int sz = sizeof(arr)/sizeof(arr[0]);
for(i=0; i<sz; i++)
printf("%d ",arr[i]);
ctsort(arr,sz,6);
printf("\n");
for(i=0; i<sz; i++)
printf("%d ",arr[i]);
return 0;
}
结果如下:
计数排序的时间复杂度为O(n+k),n为待排数组元素的个数,k为待排数组最大元素值加1。对于空间来说,需要两个n大小的数组,一个k大小的数组。
为了保证计数排序的稳定性,上面是从后往前处理待排数组arr的。
所谓稳定性,就是指如果待排数组arr中,有两个数 a[i] 和 a[j]相等,并且i<j,z在排好序以后,a[i] 仍然在 a[j] 之前。