所谓计数排序,通过字面意思理解可能就是统计序列中每个元素出现的频次、次数,然后以某种方法利用这个次数来对序列中的元素进行排序。下面我们来看看这个计数排序是怎样实现的。
假如现在有一个数组序列A 里面的元素为 2 5 4 5 0 7 1 0
2 | 5 | 4 | 5 | 0 | 7 | 1 | 0 |
第一步先找出原序列中元素的最大值(max = 7)
2 | 5 | 4 | 5 | 0 | 7 | 1 | 0 |
找到了之后我们创建一个新的数组C ,这个数组的大小为(max+1),每个元素的值都为0,在这里就是说新创建的数组有(7+1=8)个元素,每个元素都是0
0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
得到这样的C数组之后,让数组A的元素值作为数组C中元素的索引值 ,
元素值 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
索引值 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
数组A中的元素每出现一次,就给对应于C数组索引值处的元素值+1;
(就是下图这个意思)
把上面得到的结果搬下来,最终得到的计数数组C就是长下面这样的
元素值 | 2 | 1 | 1 | 0 | 1 | 2 | 0 | 1 |
索引值 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
接下来计算累加数组C
元素值 | 2 | 3 | 4 | 4 | 5 | 7 | 7 | 8 |
索引值 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
得到累加数组C之后应该怎么办呢?原来的数组又应该怎么放置呢?我们继续接着往下看
到了这里我们终于把元素2成功的放置进去,接下来把其他数也用同样的方法放在最终结果那个数组里
我们用此方法逐一将得到每个元素的位置
这就是排列得到的结果
0 | 0 | 1 | 2 | 4 | 5 | 5 | 7 |
用C++实现
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
void Print(vector<int>& v)
{
for (auto c : v)
{
cout << c << " ";
}
cout << endl;
}
void countsort(vector<int>& v, vector<int>& vv)
{
if (v.size() == 0)
return;
int len = (*max_element(v.begin(), v.end())) + 1;
vector<int> vec(len,0);
for (int i = 0; i < v.size(); ++i)
{
vec[v[i]]++;
}
for (int i = 1; i < len; ++i)
{
vec[i] += vec[i - 1];
}
for (int i = v.size(); i > 0; --i)
{
vv[--vec[v[i - 1]]] = v[i - 1];
}
}
int main()
{
vector<int> v = { 2, 5 ,4 ,5 ,0, 7 ,1 ,0 };
vector<int> vv(v.size(), 0);
cout << "before sort: ";
Print(v);
countsort(v, vv);
cout << "after sort: ";
Print(vv);
return 0;
}
实现结果
计数排序思想
1.计数排序基于一个假设,待排序数列的所有数均为整数,而且出现在(0,k)区间之内,如果区间右端点k太大,导致整个区间范围很广的话,这种方法就会引起很大的空间复杂度。
2.计数排序与比较排序不同,排序的速度快于任何比较排序算法。
3.计数排序统计<=该元素值的元素的个数i,于是该元素就放在目标元素的索引位置i处。
算法步骤
1.找出待排序数组中最大和最小的元素。
2.统计数组中每个值为i的元素出现的次数,存入数组C的第i 项
3.对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
4.填充目标数组:将每个元素i放在新数组的第c[i]项,每放一个元素就将c[i]减1