算法之路——计数排序
计数排序的可以这样简单理解:对每个输入的元素,直接确定这个元素应该放在目标数组的第几个位置,然后直接放入目标数组的合适位置。这个排序中没有用到元素之间的比较。
计数排序要求的是对于给定的元素,可以直接确定这个元素的在目标数组的合适位置。计数排序是以每个给定的元素为思考核心的。先假设任意元素在数组中比它小的元素的个数是已知的。则可假设,对输入的数据x,有i个元素是比x小。这样,x在目标数组的位置就是i+1。现在主要的问题变为怎么确定任意元素在数组中比它小的元素的个数。这个问题需要一个计数数组count[1...k],其中k是输入元素可能取到的最大值(例如,我要对n个成绩进行排序,成绩的最大值是100,那么这里的k就是100)。首先将count[]数组的每个元素初始化为0,然后对输入的元素a,执行count[a]++;当对输入的每个元素都执行完这个操作之后,如果count[b]为0,则说明输入的输入中没有b,否则输入的数据中就有b。然后从count[]数组的第二个元素开始对执行这个操作:count[i] = count[i] + count[i-1];这样count[a]中就记录下了小于等于a的元素的个数(count[1]本身既可以看做是小于等于1的个数)。所以假设的问题就解决了。
其实,计数排序从某种角度看是和简单选择排序相对称的。计数排序以特定的输入元素为中心,然后确定这个元素应放在目标数组的的哪个位置,然后直接放在目标数组的合适位置。而简单选择排序则是以目标数组的位置为中心,在目标数组中选择第i大的数据,放入目标数组的第i个位置。
以下是计数排序的代码:
#include <stdio.h>
#include <memory.h>
#include <stdlib.h>
#include <time.h>
#define MAXSIZE 1000000
#define MAX 1000 //定义数据的取值范围
int count[MAX];
int rand_num (int *s, int n);
int output (int *d, int n);
int countSort (int *s, int *d, int n);
int s[MAXSIZE];
int d[MAXSIZE];
int main ()
{
int n;
printf("请输入第一组数据的个数(输入0结束,最大1000000):");
while (scanf("%d",&n) == 1 && n != 0)
{
if (n > 10000)
printf("数据的个数过大");
rand_num(s, n);
countSort(s, d, n);
printf("原始数据:\t");
output(s, n);
printf("排序后的数据:\t");
output(d, n);
printf("请输入下一组数据的个数(输入0结束):");
}
return 0;
}
int rand_num (int *s, int n)
{
srand(time(NULL));
for (int i = 0; i < n; i++)
s[i] = rand()%1000;
return 0;
}
int output (int *d, int n)
{
for (int i = 0; i < n; i++)
printf ("%d\t",d[i]);
putchar('\n');
return 0;
}
int countSort (int *s, int *d, int n)
{
int i=0;
memset(count, 0, sizeof(count));
for (i = 0; i < n; i++)
count[s[i]]++;
for (i = 1; i < MAX; i++)
count[i] += count[i-1];
for (i = n-1; i >= 0; i--)
{
d[count[s[i]] - 1] = s[i];
count[s[i]]--;
}
return 0;
}
Keep Looking