非比较线性时间排序算法——桶排序

参考文献

排序算法(九):桶排序
本文在此基础上实现了C++版本的桶排序算法。

基本思想

桶排序的基本思想是假设数据在【min,max】之间均匀分布,其中min\max分别指数据中的最小值和最大值。那么将区间[min,max]等分成n份,这n个区间便称为n个桶。将数据加入对应的桶中,然后每个桶内单独排序。由于桶之间有大小关系,因此可以从小到大将桶中元素放入数组中。

在参考的文献中,zhipingChen 认为桶排序和快速排序以及计数排序有着一定的关联:

快速排序是将集合拆分为两个值域,这里称为两个桶,再分别对两个桶进行排序,最终完成排序。桶排序则是将集合拆分为多个桶,对每个桶进行排序,则完成排序过程。两者不同之处在于,快排是在集合本身上进行排序,属于原地排序方式,且对每个桶的排序方式也是快排。桶排序则是提供了额外的操作空间,在额外空间上对桶进行排序,避免了构成桶过程的元素比较和交换操作,同时可以自主选择恰当的排序算法对桶进行排序。

当然桶排序更是对计数排序的改进,计数排序申请的额外空间跨度从最小元素值到最大元素值,若待排序集合中元素不是依次递增的,则必然有空间浪费情况。桶排序则是弱化了这种浪费情况,将最小值到最大值之间的每一个位置申请空间,更新为最小值到最大值之间每一个固定区域申请空间,尽量减少了元素值大小不连续情况下的空间浪费情况。

算法过程

1.计算待排序集合中最大元素和最小元素的差值范围,根据差值范围确定每一个桶管辖的区域大小k,以此确定申请的桶个数 bucket_num = (max - min) / k + 1;这里的桶个数一定要加1,因为在 min 到 max之中区域跨度 max - min + 1 ,而每个桶管辖区域长度为k,结合C++整数向下取整的特性,桶个数必须加1。
2.根据映射规则 (v[i] - min) / k 将元素加入对应的桶中,这里 v[i] 指待排序集合中的第 i 个元素。
3.选择特定的比较排序算法对每个桶中的元素进行排序,最终算法复杂度与所选择的比较排序算法有关。由于此时所有元素都位于桶中,只要将元素按顺序移动回原始集合就可以了。

代码实现(桶中元素的排序方式选择堆排序)

void Bucketsort(vector<int>& v)
{
	/*记录数组中的最大值和最小值*/
	int max = v[0], min = max;
	for (auto& num : v)
	{
		if (num > max)
			max = num;
		else if (num < min)
			min = num;
	}

	//间隔设置为10,声明存放桶的数组
	int k = 10;
	int bucket_num = (max - min) / k + 1;	
	vector<vector<int>> buckets(bucket_num);

	//将元素存放进相应的桶
	for (int i = 0; i < v.size(); ++i)
		buckets[(v[i] - min) / k].push_back(v[i]);

	//依次将每个桶中的元素进行堆排序
	for (int i = 0; i < buckets.size(); ++i)
		Heapsort(buckets[i]);	//使用到上一章的堆排序

	v.clear();	//清空原数组
	//按顺序将桶中元素放回数组中
	for (int i = 0; i < buckets.size(); ++i)
		for (int j = 0; j < buckets[i].size(); ++j)
			v.push_back(buckets[i][j]);
}

算法复杂度、稳定性

将元素存放进相应的桶中,时间复杂度为O(N);对每个桶中元素进行排序,并移动回初始集合中,假设桶个数为M,平均每个桶中元素个数为 N M \frac{N}{M} MN,则时间复杂度为 O ( M ∗ N M l o g 2 N M + N ) = O ( N + N ( l o g 2 N − l o g 2 M ) ) O(M * \frac{N}{M}log_2\frac{N}{M} + N) = O(N + N(log_2N - log_2M)) O(MMNlog2MN+N)=O(N+N(log2Nlog2M))

由算法过程可知,倘若选择堆排序对桶内元素进行排序,那桶排序的时间复杂度为 O ( N + N ( l o g 2 N − l o g 2 M ) ) O(N + N(log_2N - log_2M)) O(N+N(log2Nlog2M)),当 M = = N M == N M==N时,桶排序向计数排序演化,即堆排序不发挥作用,时间复杂度为O(N),只需要将元素移动回初始集合即可。当 M = = 1 M == 1 M==1 时,即桶排序向比较排序算法演化,对集合进行堆排序,并将元素移动回初始集合,时间复杂度为 O ( N + N ( l o g 2 N ) ) O(N + N(log_2N)) O(N+N(log2N))

桶排序的空间复杂度为 O ( N + M ) O(N+M) O(N+M),其中既包括存放元素的空间N,也包括存储桶的数组空间M。算法的稳定性取决于对桶中元素排序时选择的排序算法。由桶排序的过程可知,当待排序集合中存在元素值相差较大时,对映射规则的选择是一个挑战,对算法的时间复杂度或空间复杂度有较大影响,所以同计数排序一样,桶排序适用于元素值分布较为集中的序列。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值