计数排序假设n个输入元素中的每一个都是在0到k区间内的一个整数,其中k为某个整数。计数排序的基本思想是:对每一个输入元素x,确定小于x的元素的个数。利用这一信息就可以把x直接放在它的输出
数组中的位置上。
在计数排序中,假设输入是一个数组A[1..n],A.length=n。我们还需要两个数组:B[1..n]存放排序的输出,
C
[0..k]提供存储空间。
COUNTING——SORT(A,B,k)
let C[0..k] be a new array
for i=0 to k
C[i]=0
for j=1 to A.length
C[A[j]]=C[A[j]]+1 //现在C[i]中的数是元素值等于i 的数目
for i = 1 to k
C[i]=C[i]+C[i-1] //现在C[i]是元素值小于等于i的数目
for j=A.length downto 1
B[C[A[j]]]=A[j] //从后往前把A数组中的元素放入到输出数组中合适的位置
C[A[j]]=C[A[j]]-1 //放完该元素后,把保存小于等于该元素的数组对应的值减一
算法第9行采用了从后往前的形式输出到输出数组,也可以从前开始,但是不能保证稳定性。
下面是一个算法运行的例子:
计数排序的时间代价:地3~4行的for循环所花的时间是,第4,5行所花的时间是,6~7行所花的时间是,这样总的时间代价就是。在实际工作中,当k=O(n)时,一般会采用计数排序,这样的运行时间为
实现代码如下:
#include <stdio.h>
void COUNTINGSORT(int *A, int *B, int array_size, int k)
{
int C[k+1], i, value, pos;
for(i=0; i<=k; i++)
{
C[i] = 0;
}
for(i=0; i< array_size; i++)
{
C[A[i]] ++;
}
for(i=1; i<=k; i++)
{
C[i] = C[i] + C[i-1];
}
for(i=array_size-1; i>=0; i--)
{
value = A[i];
pos = C[value];
B[pos-1] = value;
C[value]--;
}
}
int max(int arr[],int length)
{
int max=arr[0];
for (int i=1;i<length;i++)
if(max < arr[i])
max = arr[i];
return max;
}
int main()
{
int A[] = {2, 5, 3, 0, 2, 3, 0, 3}, i;
length=sizeof(A)/sizeof(A[0]);
/*
定义数组后可以用sizeof命令获得数组的长度(可容纳元素个数)。例如:
int data[4];
int length;
length=sizeof(data)/sizeof(data[0]); 数组占内存总空间,除以单个元素占内存空间大小
但是,通过传递数组名参数到子函数中,以获得数组长度是不可行的。例如:
int getLength(int[] a){
int length;
length=sizeof(a)/sizeof(a[0]); 这样是错误的,得到的结果永远是1
return length;
}
因为,a是函数参数,到了本函数中,a只是一个指针(地址,系统在本函数运行时,是不知道a所表示的地址有多大的数据存储空间,
这里只是告诉函数:一个数据存储空间首地址),所以,sizoef(a)的结果是指针变量a占内存的大小,一般在32位机上是4个字节。
a[0]是int类型,sizeof(a[0])也是4个字节,所以,结果永远是1。
因此,获得数组长度,只能在数组定义所在的代码区中,采用以上方法,才可以达到效果。
*/
int B[length];
int max=max(A,length);
COUNTINGSORT(A, B, length, max);
for (i=0; i<= 7; i++)
{
printf("%d ", B[i]);
}
printf("\n");
return 0;
}