计数排序&基数排序

在此之前我是不了解基数排序的, 昨天专门研究了下。 感觉是一种非常不错的排序算法。

时间复杂度很低o(n), 空间复杂度为o(n)。

说实话,没有多少种排序算法可以达到这样的性能。

仔细研究了下,发现在很多种情况下采用这样算法可以做到很好的处理。
(例如字符串排序, 电话号码排序等)


一、计数排序

如果想要学会基数排序, 那么首先要了解计数排序, 因为基数排序封装了计数排序。

那么对于计数排序, 我有一种很强烈的感觉就是用空间换取时间。

我想大家都知道哈希思想。

1、开辟一块很大的辅助空间(能够存储最大值), 辅助空间中的下标对应元素本身,
2、下标对应的值是该元素出现的个数。
3、最后遍历辅助空间, 累计出现的次数然后存储起来就排序成功。

非常推荐大家看这篇文章: 计数排序

Code

//版本一
vector<int> CountSort(int* arr, int len) {
   
	if (!arr || len <= 0) {
   
		return vector<int>();
	}

	int max = arr[0];
	//使得max获取最大值
	for (int i = 1; i < len; i++) {
   
		if (max < arr[i]) {
   
			max = arr[i];
		}
	}
	
	//创建辅助数组
	vector<int> tmp_arr(max + 1, 0);
	//累次出现次数
	for (int i = 0; i < len; i++) {
   
		tmp_arr[arr[i]]++;
	}
	
	//遍历辅助数组, 存储在ret_arr中返回
	vector<int> ret_arr(len);
	int index = 0;
	for (int i = 0; i < tmp_arr.size(); i++) {
   
		while (tmp_arr[i]) {
   
			ret_arr[index++] = i;
			tmp_arr[i]--;			//计数器--
		}
	}

	return ret_arr;
}

这个算法我们可以发现

1、首先获取序列中的max值。 时间复杂度为o(n)
2、开辟辅助数组空间, 空间复杂度为s(max)
3、最后遍历辅助数组, 时间复杂度为o(max),
4、还开辟了s(n)的数组, 存储遍历后有序的序列。
综上所述:时间复杂度:o(n+max); 空间复杂度:s(max+n)

我们可以发现优化核心是max值, 如果序列中只有5个元素, 但是有一个值很大, 我们都会开辟max大数组空间, 空间利用率很低。
[100, 102, 105, 107, 110] 最大值为110, 开辟从0到110大小空间。


优化一

//版本二
vector<int> CountSort1(int* arr, int len) {
   
	if (!arr || len <= 0) {
   
		return vector<int>();
	}

	int min = arr[0], max = arr[0];
	//1、获取最大值和最小值
	for (int i = 0; i < len; i++) {
   
		if (max < arr[i]) {
   
			max = arr[i];
		}
		if (min > arr[i]) {
   
			min = arr[i];
		}
	}
	
	//2、开辟辅助空间 - 统计次数
	vector<int> tmp_arr(max - min + 1, 0);
	for (int i = 0; i < len; i++) {
   
		tmp_arr[arr[i] - min]++;
	}
	
	//3、遍历辅助空间, 获取有序序列
	vector<int> ret_arr(len, 0);
	int index = 0;
	for
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值