计数排序
一、概念
基础概念:计数排序是一个非基于比较的排序算法,该算法于1954年由 Harold H. Seward 提出。它的优势在于在对一定范围内的整数排序时,它的复杂度为Ο(n+k)(其中k是整数的范围),快于任何比较排序算法。 当然这是一种牺牲空间换取时间的做法,而且当O(k)>O(nlog(n))的时候其效率反而不如基于比较的排序(基于比较的排序的时间复杂度在理论上的下限是O(nlog(n)), 如归并排序,堆排序)
通俗理解:我们以前学习的排序(如:冒泡、快排…)都是基于比较的(就是在排序过程中需要不断的根据数的大小进行比较)。而计数排序,顾名思义,它是通过计算出现的次数来进行排序。
二、代码及过程
/**
*
*计数排序
*Date:2019年5月4日
*
***/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void countSort(int *a,int n){
int max = a[0];
int min = a[0];
// 1.找出当前数组中最大和最小元素
for(int i = 1; i < n; i++){
if(a[i] > max){
max = a[i];
}
else if(a[i] < min){
min = a[i];
}
}
// 2.分配max-min+1的辅助数组空间(如:[5,15]范围内的数,就需要15-5+1的存储空间)
int *temp = (int *)malloc(sizeof(int) * (max - min + 1));
memset(temp,0,sizeof(int) * (max - min + 1));
// 3.计数
for(i = 0; i < n; i++){
temp[a[i]-min]++;
}
// 4.排序原数组
int sub = max - min;
int k = 0;
for(i = 0; i <= sub; i++){
for(int j = 0; j < temp[i]; j++){
a[k++] = i + min;
}
}
}
void show(int *a,int n){
int i;
for(i = 0; i < n; i++){
printf("%3d",a[i]);
}
}
void main(){
int a[] = {7,8,5,9,12,15,6,9,6};
int n = sizeof(a) / sizeof(a[0]);
printf("\n排序前:\n");
show(a,n);
// 计数排序
countSort(a,n);
printf("\n排序后:\n");
show(a,n);
printf("\n");
}
三、复杂度
如果原数组的长度为n,最大值和最小值的差值为k,则:
时间复杂度: O(n + k)
空间复杂度: O(k)
四、其他
需注意:
-
如果最大值和最小值之差很大的话,那么使用计数排序反而效果更为低。
(k值变得很大的话,O(n+k) 的时间复杂度还不如 O(nlogn),并且会浪费大量的存储空间)
如: 对十个数进行排序,其中最大值为1亿,最小值为1。 -
计数排序不能对含有小数的数进行排序,如:0.34564、1.5454、0.66666…