经典排序—计数排序算法
一、前言
O(nlogn)
。但是,它需要用额外的内存空间来暂时储存归并过程中的元素,因此我们可以认为归并排序是以牺牲一部分内存空间为代价来获得时间的高效性。
O(N)
。
他快于任何比较排序算法。 当然这是一种牺牲空间换取时间的做法。它适用于范围较小的整数序列。
二、算法描述
max,
最小值记为
min
。
count
,其长度是
max - min + 1
,其元素默认值都为
0
。
count
数组的索引,以原数组中的元素出现次数作为
count
数组的元素值。
result
,其大小跟原始数组一样
。
count
数组,
将其对应的索引作为元素值填充到
result
数组中去
。
result
。
三、举个栗子
我们以从小到大排序为例,对下图所示的数组进行计数排序:
我们对其进行统计,统计结果如下:
看到这样的结果大家是不是有点懵???
最大值 - 最小值 + 1
可得到计数数组的长度为:
7-0+1 = 8
count
结果如下:
1
,
其表示的含义是值为
0
在原始数组中出现的次数为
1
次;第二个位置存放的元素是
1
,
其表示的含义是值为
1
在原始数组中出现的次数为
1
次;第三个位置存放的元素是
2
,其表示的含义是值为
2
在原始数组中出现的次数为
2
次,以此类推.....
创建数组 result :
遍历count
数组进行排序:
我们根据统计结果对其排序,如下图所示,红色结点
表示已经排序的值。
四、算法实现
#include <iostream>
using namespace std;
int Arr[] = { 3, 3, 5, 2, 1, 0, 7, 2, 5, 4, 4, 7, 3};
int cnt[ 8];
int main(){
for ( int i= 0; i< 13; i++){
cnt[Arr[i]]++;
}
for( int i= 0; i< 8; i++){
for( int j= 0; j<cnt[i]; j++){
cout << i << " ";
}
}
return 0;
}
输出:
五、算法分析
O(n+k)
,整个过程需要遍历两次数组,一次是遍历长度为
n
的数组,另一次是从计数器(假设有
k
个计数器)中遍历,因此时间复杂度为
O(n+k)
k
的额外数组,故空间复杂度为
O(k)
。
六、适用场景
这是因为其当数组元素的范围太大时,并不适合计数排序,不仅浪费时间,效率还会大大降低。
当待排序的元素非整数时,也不适用,大家思考一下这是为什么呢?
推荐阅读
• • • • •
•