计数排序

计数排序是一种非比较性质的排序算法,元素从未排序状态变为已排序状态的过程,是由额外空间的辅助和元素本身的值决定的。计数排序过程中不存在元素之间的比较和交换操作,根据元素本身的值,将每个元素出现的次数记录到辅助空间后,通过对辅助空间内数据的计算,即可确定每一个元素最终的位置。

计数排序涉及到3个数组

数组A:原始的待排序数组

数组C:A数组的元素的值A[i]是C数组的下标C[A[i]],对应的值C[A[i]]=A数组中小于等于A[i]的元素的个数

数组B:对A进行排序之后的有序数组

算法过程:

  1. 根据待排序数组A中最大元素K的值,申请额外的K+1个空间,构成数组C;
  2. 遍历待排序数组A,将每一个元素A[i]出现的次数记录到以A[i]为下标的数组C中;
  3. 对数组C进行遍历,计算每小于等于A[i]的元素的个数;
  4. 再次遍历数组A,结合C数组,得到A[i]在B数组的正确位置。

算法示例:

#include<iostream>
#include<vector>
using namespace std;

int main()
{
	int A[10]={1,8,6,5,6,2,5,5,8,1};
	vector<int> B(10,0);
	int k=8;    //待排序数组中元素的最大值
	vector<int> C(k+1,0);    // 数组C的长度是k+1,不是k
	for(int i=0;i<10;i++)  //遍历A数组,获取每个元素的重复个数,记录在数组C中
		C[A[i]]++;
	for(int i=1;i<=k;i++) //遍历C数组,计算小于等于A[i]的元素的个数
		C[i]+=C[i-1];
	for(int i=9;i>=0;i--)  //倒着遍历数组A,保证算法的稳定性。得到每个元素在B数组中的正确位置
	{
		C[A[i]]--;
		B[C[A[i]]]=A[i];
	}
	return 0;
}

算法分析:

由算法示例可知,排序的时间为2*N+K,所以时间复杂度为O(n+k),辅助空间为O(n+k),由此可知,计数排序是一种以空间换时间的排序算法,时间复杂度是线性的,且只使用于K值比较小的情况,当K值较小时,计数排序的优势较明显,当K值较大时,就不如其他排序算法优秀(如快排)。

注意:由于要用元素的值做下标,所以该算法只能对整数进行排序。如果待排序序列中有负数,最小负数为m,则将数组中的每个元素都加上|m|,使最小的元素变为0,然后再排序,并在放入B数组时,记得再减去|m|

这是一种稳定的排序算法,因为相同的数的相对位置在排序前后不变

附加一道题:

O(N+K)

k=3,所以C数组的长度为k+1=4,选A

经典排序算法 - 基数排序Radix sort

原理类似桶排序,这里总是需要10个桶,多次使用

首先以个位数的值进行装桶,即个位数为1则放入1号桶,为9则放入9号桶,暂时忽视十位数

例如

待排序数组[52,14,49,68,16]简单点五个数字

分配10个桶,桶编号为0-9,以个位数数字为桶编号依次入桶,变成下边这样

|  0  |  0  | 52 |  0  | 14 |  0  | 16 |  0  |  68 | 49 |

|  0  |  1  |  2  |  3  |  4 |  5  |  6  |  7  |  8  |  9  |桶编号

将桶里的数字顺序取出来,

输出结果:[52,14,16,68,49]

再次入桶,不过这次以十位数的数字为准,进入相应的桶,变成下边这样:

由于前边做了个位数的排序,所以当十位数相等时,个位数字是由小到大的顺序入桶的,就是说,入完桶还是有序

|  0  | 14,16 |  0  |  0  |  49  | 52 | 68  | 0  | 0 |  0  |

|  0  |  1      |  2  |  3  |  4  |  5  |  6  |  7  |  8  |  9  |桶编号

因为没有大过100的数字,没有百位数,所以到这排序完毕,顺序取出即可

最后输出结果:[14,16,49,52,68]

经典排序算法 - 桶排序Bucket sort

1,桶排序是稳定的

2,桶排序是常见排序里最快的一种,比快排还要快…大多数情况下

3,桶排序非常快,但是同时也非常耗空间,基本上是最耗空间的一种排序算法

桶排序的原理:将数字放在相同编号的桶里,如5放在5号桶,10放在10号桶,100放在100号桶,C[A[i]]=A[i],所以,桶的个数是待排序元素的最大值K,辅助数组长度的长度为K+1(没有重复元素用一维数组就可以,有重复元素的用二维数组),所以这是一种非常耗费空间的算法

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值