简述
拿空间换时间的典型算法。以新构建的数组的下标标识原数组的某个数,以新构建的数组中该下标所对应的值记录原数组中该值出现的次数,然后构建新的数组以实现排序。
实现
void algorithm(void)
{
int max = 0;
for(int i = 0;i < DATA_AMOUNT;i++) if(nums[i] > max) max = nums[i];
int i,j = 0;
int* count = (int*)calloc(sizeof(int),max + 1);// 放在堆里,防止爆栈
if(!count) abort();
memset(count,0,sizeof(int) * (max + 1));
for(i = 0;i < DATA_AMOUNT;i++) count[nums[i]]++;
for(i = 0;i < max + 1;i++) while(count[i]-- > 0) nums[j++] = i;
}
完整代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <limits.h>
#define DATA_AMOUNT 50000
#define ALGORITHM_NAME "O(n)查找最大值 + 计数排序 (Counting Sort)"
int nums[DATA_AMOUNT];
void algorithm(void);
int main(void)
{
for(int i = 0;i < DATA_AMOUNT;i++) nums[i] = rand()%10001;//(0,10000)
int start,end;
start = clock();
algorithm();
end = clock();
printf("algorithm \"%s\" used %f sec to process %d data\n",ALGORITHM_NAME,(float)(end - start)/CLOCKS_PER_SEC,DATA_AMOUNT);
for(int i = 0;i < DATA_AMOUNT - 1;i++)
{
if(nums[i] > nums[i+1])
{
puts("FAILED");
abort();
}
}
puts("PASSED");
return 0;
}
void algorithm(void)
{
int max = 0;
for(int i = 0;i < DATA_AMOUNT;i++) if(nums[i] > max) max = nums[i];
int i,j = 0;
int* count = (int*)calloc(sizeof(int),max + 1);// 放在堆里,防止爆栈
if(!count) abort();
memset(count,0,sizeof(int) * (max + 1));
for(i = 0;i < DATA_AMOUNT;i++) count[nums[i]]++;
for(i = 0;i < max + 1;i++) while(count[i]-- > 0) nums[j++] = i;
}
测试结果
第一次 | 第二次 | 第三次 | 平均 |
---|---|---|---|
0.000335 sec | 0.000297 sec | 0.000360 sec | 0.000331 sec |
性能分析
-
该算法未进行任何数值比较,相比冒泡等基于比较的算法有明显优势。
-
该算法时间复杂度为 O ( n + k ) O(n+k) O(n+k)
-
该算法使用格外空间以换取更少的时间消耗
-
该算法不稳定,若要实现稳定性,需要格外编写代码。