【算法】计数排序

算法-计数排序


前置知识
  • 数组
  • STL 中的 map 类型

思路

这是一个很鬼畜的算法,请做好心理准备。。。

我们现在有一个序列,怎么对它排序?
这是一个非常经典的问题,这里我们使用一个经典的基础算法——计数排序解决。

我们有一个序列,要进行升序排序。
7 3 1 7 4 3 \begin{array}{cc} 7&3&1&7&4&3 \end{array} 731743
我们建立一个数组,为对应每个数出现的次数。
依次用序列元素更新数组。
最后,我们得到下面这个数组:
1 2 3 4 5 6 7 1 0 2 1 0 0 2 \begin{array}{cc} 1&2&3&4&5&6&7\\\\ 1&\gray0&2&1&\gray0&\gray0&2 \end{array} 11203241506072
然后从小到大,在答案序列中加入相应个数的元素。
1 3 3 4 7 7 \begin{array}{cc} 1&3&3&4&7&7 \end{array} 133477
完成


算法参数
  • 平均时间复杂度: O ( n ) O(n) O(n)
  • 最好时间复杂度: O ( n ) O(n) O(n)
  • 最坏时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( max ⁡ ( a ) ) O(\max(a)) O(max(a))

极端情况

如果数据过大,计数排序的数组可能开不下。
比如:
2000000000 1000000000 \begin{array}{cc} 2000000000&1000000000 \end{array} 20000000001000000000
显然不可能将数组开到 2000000000 2000000000 2000000000


优化

我们考虑使用 STL 中的 map 类型来偷懒解决。
只需要使用 iterator 遍历 map 就可以做到 O ( n log ⁡ n ) O(n\log n) O(nlogn) 了。
但是 map 是使用红黑树维护的,所以相当于堆排序


算法参数
  • 平均时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)
  • 最好时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)
  • 最坏时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)
  • 空间复杂度: O ( n ) O(n) O(n)

实现代码
  • 基础版本
void CountSort(int a[],int n){//计数排序
	int mx=a[1],mn=a[1];//最大与最小元素
	for (int i=2;i<=n;i++) mx=max(mx,a[i]),mn=min(mn,a[i]);
	int tmp[mx-mn+10];//计数数组
	for (int i=0;i<=mx-mn;i++) tmp[i]=0;//初始化
	for (int i=1;i<=n;i++) tmp[a[i]-mn]++;//将数量加1
	int k=0;//数组指针
	for (int i=0;i<=mx-mn;i++)//遍历数组
		for (int j=1;j<=tmp[i];j++)
			a[++k]=i+mn;//取出
}
  • 优化版本
void CountSort(int a[],int n){//计数排序
	map<int,int> tmp;//计数数组
	for (int i=1;i<=n;i++)
		tmp[a[i]]++;//将数量加1
	map<int,int>::iterator it;//map指针
	int k=0;//数组指针
	for (it=tmp.begin();it!=tmp.end();it++)//遍历map
		for (int i=1;i<=it->second;i++)
			a[++k]=it->first;//取出
}

练习
  • 洛谷P1177 【模板】排序

你可能感兴趣的:(算法,#,排序,算法,排序算法)