计数排序 可在线性时间 即O(n)时间内完成排序。而前几节中的排序,如插入排序、归并排序、快速排序、堆排序、希尔排序这几种
都属于比较排序,即是排序中均通过比较的方法,且可以证明无论何种比较排序,总的比较次数下确界为 O(nlogn),性能无法再提高
计数排序是线性时间内完成的排序,其基本思想:
不通过元素的比较,而是通过统计比元素data[i]或者大的元素有多少个,知道这个信息等于知道data[ i ]插入的位置
而统计的基本方法 就是计数。
假设知道待排序的数组 中数值的最大值,即假定data[] 数据,最大值为K,分布为0 ~ k
所以需要一个临时的计数数组cnt[]来统计 data[]中没一个数值有多少个 则length( cnt[] )=k+1;
还需要一个与 data 同样长度的数组 newdata[]来将data[ ]中的元素,根据cnt[ ]的信息插入到 newdata中去
这就是计数排序的基本思想及步骤。
下面用代码实现:
为了使思路更清晰,代码比较多,可以优化:对于纯粹数组,则newdata可以省略实现原地排序,因为cnt的下标即为data元素数值,对于其他结构则不可以
/*********** counting sort***************/
void CountingSort(int data[],int len,int k) //the value of data distribute from 0 to k k is the max value
{
int *cnt=(int*)malloc((k+1)*sizeof(int)); // get array memory
int *newdata=(int*)malloc(len*sizeof(int)); //new data
int i;
for (i=0;i<=k;i++) //assign cnt array
cnt[i]=0;
for (i=0;i<len;i++) //包含等于i的元素个数
cnt[data[i]]++;
for (i=1;i<=k;i++) //包含小于等于i的元素个数
cnt[i]+= cnt[i-1];
for (i=len-1;i>=0;i--) //根据cnt array直接赋值给newdata,即可完成排序
{
newdata[cnt[data[i]]-1]=data[i]; //-1是因为数组下标从0开始
cnt[data[i]]--;
}
for (i=0;i<len;i++) //重新赋值给原数组
data[i]=newdata[i];
free(cnt);
free(newdata);
}
算法分析:主要分为两部分,以上cnt的赋值操作 运行时间为O(K),后面是data的计数操作,运行时间为O(N),
故总的运行时间为O(k+n)
虽然计数排序能在线性时间内完成排序,效率极高,但必须知道待排序数据的范围,以及待排序数据分布不可以太零散,需比较集中