计数排序
目录
计数排序
输入n个元素,范围是0-k的整数,统计出0-k每个元素有多少个,反向遍历,对于每个元素a,统计出小于等于a的元素有几个,将a填充到对应的位置
一定要反向遍历,不然不稳定
过程演示
简单做了一个fgif,gif下面有图解
假如我们有一个数组a[10],范围都是0-10的整数
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
a | 7 | 7 | 6 | 0 | 9 | 0 | 5 | 6 | 7 | 8 |
先创建出一个数组c,遍历数组a,统计一下每个元素有多少个
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 0 | 0 | 0 | 0 | 1 | 2 | 3 | 1 | 1 |
对c求前缀和,对于每个i,小于等于i的元素有c[i]个
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 2 | 2 | 2 | 2 | 3 | 5 | 8 | 9 | 10 |
创建一个临时数组b[10]用来输出最终结果,反向遍历数组a,对于每个元素a[i],小于等于a[i]的元素有c[a[i]]个,那么a[i]的最终位置是c[a[i]]-1(如果下标从1开始,那么最终位置就是c[a[i]])
i=8,a[i]=8,c[8]=9,小于等于8的元素有9个,所以b[8]=a[i]=8
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
b | 8 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 2 | 2 | 2 | 2 | 3 | 5 | 8 | 9 | 10 |
c[8]--,因为已经填充了一个,所以要-1
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 2 | 2 | 2 | 2 | 3 | 5 | 8 | 8 | 10 |
i=7,a[i]=7,c[7]=8,小于等于7的元素有8个,所以b[7]=a[i]=7
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
b | 7 | 8 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 2 | 2 | 2 | 2 | 3 | 5 | 8 | 9 | 10 |
c[7]--
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 2 | 2 | 2 | 2 | 3 | 5 | 7 | 9 | 10 |
i=7,a[i]=6,c[6]=5,小于等于6的元素有5个,所以b[4]=a[i]=6
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
b | 6 | 7 | 8 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 2 | 2 | 2 | 2 | 3 | 5 | 7 | 9 | 10 |
c[6]--
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 2 | 2 | 2 | 2 | 3 | 4 | 7 | 9 | 10 |
i=6,a[i]=5,c[5]=3,小于等于5的元素有3个,所以b[2]=a[i]=5
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
b | 5 | 6 | 7 | 8 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 2 | 2 | 2 | 2 | 3 | 4 | 7 | 9 | 10 |
c[5]--
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 2 | 2 | 2 | 2 | 2 | 4 | 7 | 9 | 10 |
i=5,a[i]=0,c[0]=2,小于等于0的元素有2个,所以b[1]=a[i]=0
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
b | 0 | 5 | 6 | 7 | 8 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 2 | 2 | 2 | 2 | 2 | 2 | 4 | 7 | 9 | 10 |
c[0]--
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 1 | 2 | 2 | 2 | 2 | 2 | 4 | 7 | 9 | 10 |
i=4,a[i]=9,c[9]=10,小于等于9的元素有10个,所以b[9]=a[i]=9
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
b | 0 | 5 | 6 | 7 | 8 | 9 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 1 | 2 | 2 | 2 | 2 | 2 | 4 | 7 | 9 | 10 |
c[9]--
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 1 | 2 | 2 | 2 | 2 | 2 | 4 | 7 | 9 | 9 |
i=3,a[i]=0,c[0]=3,小于等于0的元素有1个,所以b[0]=a[i]=0
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
b | 0 | 0 | 5 | 6 | 7 | 8 | 9 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 1 | 2 | 2 | 2 | 2 | 2 | 4 | 7 | 9 | 9 |
c[0]--
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 0 | 2 | 2 | 2 | 2 | 2 | 4 | 7 | 9 | 9 |
i=2,a[i]=6,c[6]=4,小于等于6的元素有4个,所以b[3]=a[i]=6
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
b | 0 | 0 | 5 | 6 | 6 | 7 | 8 | 9 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 0 | 2 | 2 | 2 | 2 | 2 | 4 | 7 | 9 | 9 |
c[6]--
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 0 | 2 | 2 | 2 | 2 | 2 | 3 | 7 | 9 | 9 |
i=1,a[i]=7,c[7]=7,小于等于7的元素有7个,所以b[6]=a[i]=7
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
b | 0 | 0 | 5 | 6 | 6 | 7 | 7 | 8 | 9 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 0 | 2 | 2 | 2 | 2 | 2 | 3 | 7 | 9 | 9 |
c[7]--
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 0 | 2 | 2 | 2 | 2 | 2 | 3 | 6 | 9 | 9 |
i=0,a[i]=7,c[7]=6,小于等于7的元素有6个,所以b[5]=a[i]=7
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
b | 0 | 0 | 5 | 6 | 6 | 7 | 7 | 7 | 8 | 9 |
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 0 | 2 | 2 | 2 | 2 | 2 | 3 | 6 | 9 | 9 |
c[7]--
index | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
c | 0 | 2 | 2 | 2 | 2 | 2 | 3 | 5 | 9 | 9 |
代码
#include<iostream>
#include<cstring>
void countingSort(int a[], int n) {
//找到最大的元素,如果知道范围就不用这一步了,直接开c数组就好了
int maxNum = a[0];
for (int i = 1; i < n; ++i)
if (a[i] > maxNum)maxNum = a[i];
int* c = new int[maxNum + 1];
memset(c, 0, sizeof(int)*(maxNum + 1));
//统计每个元素有几个
for (int i = 0; i < n; ++i)++c[a[i]];
//前缀和
for (int i = 1; i <= maxNum; ++i)c[i] += c[i - 1];
int* b = new int[n];
//反向填充
for (int i = n - 1; i >= 0; --i) {
//两种实现
/*
第一种
b[c[a[i]] - 1] = a[i];
--c[i];*/
//第二种
b[--c[a[i]]] = a[i];
}
//复制回去
memcpy(a, b, sizeof(int)*n);
//for (int i = 0; i < n; ++i)a[i] = b[i];
delete[] b;
delete[] c;
}
时间复杂度,O(n+k)k是数组中的最大值
稳定性:稳定
上一篇: 揭秘:你知道曹操生平最恨的人是谁吗?