原理:
假设待排序序列没有负数。对序列里面的所有元素,确定比该元素小的元素有几个。利用这个信息就能知道该元素应该放在哪个位置上。
举例:
1 | 7 | 5 | 5 | 2 | 3 | 9 | 3 | 5 | 6 |
A序列(待排序)
0 | 1 | 1 | 2 | 0 | 3 | 1 | 1 | 0 | 1 |
然后我们对B序列相邻两个元素进行相加,相加后的数字放在下标较大的位置里。
0 | 1 | 2 | 4 | 4 | 7 | 8 | 9 | 9 | 10 |
然后我们对A序列逆序便利一下,结果放在C序列里面。
倒数第一个为6,找到B序列下标为6的位置,里面的值为8,说明这个元素应该排在第七个位置上。
6 |
B序列对应的第六个位置的元素-1。避免相同的数字。
0 | 1 | 2 | 4 | 4 | 7 | 7 | 9 | 9 | 10 |
倒数第二个为5,找到B序列下标为5的位置,里面的值为7,说明这个元素应该排在第六个位置上。
5 | 6 |
C序列
B序列对应的第五个位置的元素-1。
0 | 1 | 2 | 4 | 4 | 6 | 7 | 9 | 9 | 10 |
倒数第三个为3,找到B序列下标为3的位置,里面的值为4,说明这个元素应该排在第三个位置上。
3 | 5 | 6 |
B序列对应的第三个位置的元素-1。
0 | 1 | 2 | 3 | 4 | 6 | 7 | 9 | 9 | 10 |
倒数第四个为9,找到B序列下标为9的位置,里面的值为10,说明这个元素应该排在第九个位置上。
3 | 5 | 6 | 9 |
B序列对应的第九个位置的元素-1。
0 | 1 | 2 | 3 | 4 | 6 | 7 | 9 | 9 | 9 |
倒数第五个为3,找到B序列下标为3的位置,里面的值为3,说明这个元素应该排在第二个位置上。
3 | 3 | 5 | 6 | 9 |
B序列对应的第三个位置的元素-1。
0 | 1 | 2 | 2 | 4 | 6 | 7 | 9 | 9 | 9 |
倒数第六个为2,找到B序列下标为2的位置,里面的值为2,说明这个元素应该排在第一个位置上。
2 | 3 | 3 | 5 | 6 | 9 |
B序列对应的第二个位置的元素-1。
B序列
0 | 1 | 1 | 2 | 4 | 6 | 7 | 9 | 9 | 9 |
倒数第七个为5,找到B序列下标为5的位置,里面的值为6,说明这个元素应该排在第五个位置上。
2 | 3 | 3 | 5 | 5 | 6 | 9 |
B序列对应的第五个位置的元素-1。
0 | 1 | 1 | 2 | 4 | 5 | 7 | 9 | 9 | 9 |
倒数第八个为5,找到B序列下标为5的位置,里面的值为5,说明这个元素应该排在第四个位置上。
2 | 3 | 3 | 5 | 5 | 5 | 6 | 9 |
B序列对应的第五个位置的元素-1。
0 | 1 | 1 | 2 | 4 | 4 | 7 | 9 | 9 | 9 |
倒数第九个为7,找到B序列下标为7的位置,里面的值为9,说明这个元素应该排在第八个位置上。
2 | 3 | 3 | 5 | 5 | 5 | 6 | 7 | 9 |
B序列对应的第七个位置的元素-1。
0 | 1 | 1 | 2 | 4 | 4 | 7 | 8 | 9 | 9 |
倒数第十个为1,找到B序列下标为1的位置,里面的值为1,说明这个元素应该排在第零个位置上。
1 | 2 | 3 | 3 | 5 | 5 | 5 | 6 | 7 | 9 |
B序列对应的第一个位置的元素-1。
0 | 0 | 1 | 2 | 4 | 4 | 7 | 8 | 9 | 9 |
代码:
void CountSort(int a[], int nlen)
{
int temp = a[0];
for (int i = 0; i != nlen; ++i)
{
if (temp < a[i])
{
temp = a[i];
}
}
int b_size = temp + 1;
int *b = new int[b_size];
for (int i = 0; i != b_size; ++i)
{
b[i] = 0;
}
for (int i = 0; i != nlen; ++i)
{
++b[a[i]];
}
for (int i = 1; i != b_size; ++i)
{
b[i] += b[i - 1];
}
int *c = new int[nlen];
for (int i = nlen-1; i >= 0; --i)
{
c[--b[a[i]]] = a[i];
}
for (int i = 0; i != nlen; ++i)
{
a[i] = c[i];
}
delete[] b;
b = nullptr;
delete[] c;
c = nullptr;
}
总结:
计数排序的思想很简单,并且是已常量时间完成的排序,时间复杂度为O(N),但是缺陷也很明显,其一,必须是大于等于0的元素,当有数字为负数的时候,可以给每个元素都加上一个正数,使得待排序序列为正数,排完后再减去这个正数(前提不越界的情况下)。其二,该排序算法浪费了大量的空间来换取时间。例如有99999的元素,那么B序列也应该有100000的长度。