计数排序-非比较排序
计数排序是一个稳定的排序算法,输入元素是n个 0到k的直接的整数时,时间复杂度是O(n)
,空间复杂度也是O(n),其排序速度是超过任何比较算法的,但是运用场景比较局限,只有当k不是很大,并且序列比较集中时,计数排序是一个很有效的排序算法。
第一版
#include <stdio.h>
#include <stdlib.h>
void print_array(int *a, int len) {
for (int i = 0; i < len; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
void counting_sort(int *a, int size, int max) {
int *bucket = (int *)calloc(max+1, sizeof(int));
for ( int i = 0; i < size; i++ ) {
bucket[a[i]]++;
}
print_array(bucket, 10);
for (int i = 0, j = 0; i < max+1; i++) {
while ( bucket[i] > 0 ) {
a[j++] = i;
bucket[i]--;
}
}
free(bucket);
}
int main() {
int a[10] = {1, 2, 1, 2, 3, 6, 8, 9, 5, 7};
print_array(a, 10);
counting_sort(a, 10, 9);
print_array(a, 10);
return 0;
}
以上排序存在问题
- 不能对负整数排序
- 整数间隔太大时,及其浪费空间
- 且是不稳定排序的
改进版
#include <stdio.h>
#include <stdlib.h>
void print_array(int *a, int len) {
for (int i = 0; i < len; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
void counting_sort(int *a, int size) {
int max = a[0], min = a[0];
//寻找最值 O(n)
for (int i = 1; i < size; i++) {
if ( a[i] > max ) {
max = a[i];
}
if ( a[i] < min ) {
min = a[i];
}
}
//额外内存,存储次数(从左到右)
int *counts = (int *)calloc(max-min+1, sizeof(int));
for ( int i = 0; i < size; i++ ) {
counts[ a[i] - min ]++;
}
print_array(counts, max-min+1);
//累加次数
for (int i = 1; i < max-min+1; i++ ) {
counts[i] += counts[i-1];
}
print_array(counts, max-min+1);
//从右向左复制到新数组
int *new = (int *)calloc(size, sizeof(int));
for (int i = size-1; i >= 0; i--) {
new[--counts[a[i]-min]] = a[i];
}
print_array(new, size);
for (int i = 0; i < size; i++) {
a[i] = new[i];
}
free(counts);
free(new);
}
int main() {
int a[10] = {-3, 2, 1, 2, 3, 6, 8, 9, 5, -3};
print_array(a, 10);
counting_sort(a, 10);
print_array(a, 10);
return 0;
}
/** 执行结果
-3 2 1 2 3 6 8 9 5 -3 //初始化数组
2 0 0 0 1 2 1 0 1 1 0 1 1 //初次计数
2 2 2 2 3 5 6 6 7 8 8 9 10 //累加计数
-3 -3 1 2 2 3 5 6 8 9 //根据累加数从右往左计算坐标值
-3 -3 1 2 2 3 5 6 8 9 //最终输出
*/
稳定排序,空间复杂度与时间复杂度都为 O(n+k)