8.计数排序(Counting Sort)
计数排序的核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。
作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。
(1)算法简介:是一种稳定的排序算法。计数排序使用一个额外的数组C,其中第i个元素是待排序数组A中值等于i的元素的个数。然后根据数组C来将A中的元素排到正确的位置。它只能对整数进行排序。
(2)算法描述和实现:具体算法描述如下:
<1>. 找出待排序的数组中最大和最小的元素;
<2>. 统计数组中每个值为i的元素出现的次数,存入数组C的第i项;
<3>. 对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加);
<4>. 反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1。
(3)算法分析:当输入的元素是n 个0到k之间的整数时,它的运行时间是 O(n + k)。计数排序不是比较排序,排序的速度快于任何比较排序算法。由于用来计数的数组C的长度取决于待排序数组中数据的范围(等于待排序数组的最大值与最小值的差加上1),这使得计数排序对于数据范围很大的数组,需要大量时间和内存。
最佳情况:T(n) = O(n+k); 最差情况:T(n) = O(n+k) 平均情况:T(n) = O(n+k)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <assert.h>
#define RANDMAX 1000000
#define RANDMIN 900000
void getRandArray(int array[], int size);
void countSort(int array[], int size);
void isSorted(int array[], int size);
int main(int argc, char const *argv[])
{
int size = 0;
scanf("%d", &size);
assert(size > 0);
int *array = (int *)calloc(size, sizeof(int));
getRandArray(array, size);
clock_t begin;
clock_t end;
begin = clock();
countSort(array, size);
end = clock();
//打印排序所花费的时间,在linux下单位为ms
printf("%ld\n", (end - begin) / 1000);
isSorted(array, size);
free(array);
return 0;
}
//利用伪随机数填充数组array,伪随机数的范围在RANDMIN~RANDMAX-1之间
void getRandArray(int array[], int size)
{ assert(array != NULL && size > 0);
srand((unsigned) time(NULL));
int i = 0;
for (i = 0; i < size; ++i) {
array[i] = rand() % (RANDMAX - RANDMIN) + RANDMIN ;
}
}
//从小到大进行排序
void countSort(int array[], int size)
{ assert(array != NULL && size > 0);
//计数数组,用于统计数组array中各个不同数出现的次数
//由于数组array中的数属于0...RANDMAX-1之间,所以countArray的大小要够容纳RANDMAX个int型的值
int *countArray = (int *) calloc(RANDMAX, sizeof(int));
//用于存放已经有序的数列
int *sortedArray = (int *) calloc(size, sizeof(int));
//统计数组array中各个不同数出现的次数,循环结束后countArray[i]表示数值i在array中出现的次数
int index = 0;
for (index = 0; index < size; ++index) {
countArray[array[index]]++;
}
//统计数值比index小的数的个数,循环结束之后countArray[i]表示array中小于等于数值i的元素个数
for (index = 1; index < RANDMAX; ++index) {
countArray[index] += countArray[index - 1];
}
for (index = size - 1; index >= 0; --index) {
//因为数组的起始下标为0,所以要减一
sortedArray[countArray[array[index]] - 1] = array[index];
//这里减一是为了保证当有多个值为array[index]的元素时,后出现的值为array[index]的元素
//放在后面,也就是为了保证排序的稳定性
--countArray[array[index]];
}
memcpy(array, sortedArray, size * sizeof(int));
free(sortedArray);
free(countArray);
}
//判断数组array是否已经是有序的
void isSorted(int array[], int size)
{ assert(array != NULL && size > 0);
int unsorted = 0;
int i = 0;
for (i = 1; i < size; ++i) {
if (array[i] < array[i - 1]) {
unsorted = 1;
break;
}
}
if (unsorted) {
printf("the array is unsorted!\n");
} else {
printf("the array is sorted!\n");
}
}