C++实现排序算法之基数排序

一、算法思想
基数排序是一种非比较型整数排序算法,其原理是将众多数字按位分隔后进行排序。
实现步骤:
1.将所有待比较的数字(正整数)统一为同一长度,位数不够的数字前面补0;
2.按照从个位,十位,百位······从低到高的顺序进行排序
3.完成从低位到高位的排序后,待排序数字也就完成了排序
具体举例说明:
初始化序列num{57, 123, 564, 32, 0, 56, 169, 5, 23, 11, 100}
将上述序列的数字按照个位数字进行排序,个位数字取值范围0-9,我们可以将其设置为数组用来存储序列中的数字,如下所示
按照个位进行排序的数字
然后我们将这些数字按照个位再取出来得到新的序列num_new{0, 100, 11, 32,123, 23, 564, 5, 56, 57, 169},下面按照十位,百位继续进行排序,结束后便是有序数列
动态效果示意图如下
在这里插入图片描述
用代码实现的思路:
1.计算出得到的序列中的位数最大的数字的位数,以便确定需要进行几次排序
2.创建取出任意数字任意位数的函数,用于对数字的排序
3.接下来便可以开始排序
C++代码如下:

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


int MaxBit(vector<int> input)    //求出数组中最大数的位数
{
	int max_num = input[0];      //默认最大数为第一个数字
	for (int i = 0; i < input.size(); i++)  //找出数组中的最大数
	{
		if (input[i] > max_num)
		{
			max_num = input[i];
		}
	}
	int p = 0;
	while (max_num > 0)
	{
		p++;
		max_num /= 10;   //每次除以10取整,即可去掉最低位
	}
	return p;
}

int GetNum(int num, int d)   //取出所给数字的第d位数字
{
	int p = 1;
	while (d - 1 > 0)
	{
		p *= 10;
		d--;
	}
	return num / p % 10;
}

vector<int> RadixSort(vector<int> input, int length)   //基数排序
{
	vector<int> bucket(length);   //创建临时存放排序过程中的数据
	vector<int> count(10);   //创建按位计数的技术容器,即记录排序中按个位、十位...各个数的位置的个数

	for (int d = 1; d <= MaxBit(input); d++) {
		// 计数器清0
		for (int i = 0; i < 10; i++) {
			count[i] = 0;
		}

		// 统计各个桶中的个数
		for (int i = 0; i < length; i++) {
			count[GetNum(input[i], d)]++;
		}

		for (int i = 1; i < 10; i++) {     //得到每个数应该放入bucket中的位置
			count[i] += count[i - 1];
		}

		for (int i = length - 1; i >= 0; i--) {  //采用倒序进行排序是为了不打乱已经排好的顺序
			int k = GetNum(input[i], d);
			bucket[count[k] - 1] = input[i];
			count[k]--;
		}


		for (int j = 0; j < length; j++)    // 临时数组复制到 input 中
		{
			input[j] = bucket[j];
		}
	}
	return input;
}

int main()
{
	int arr[] = { 50, 123, 543, 187, 49, 30, 0, 2, 11, 100 };
	vector<int> test(arr, arr + sizeof(arr) / sizeof(arr[0]));
	cout << "排序前:";
	for (int i = 0; i < test.size(); i++) {
		cout << test[i] << " ";
	}
	cout << endl;

	vector<int> result = test;
	result = RadixSort(result, result.size());
	cout << "排序后:";
	for (int i = 0; i < result.size(); i++) {
		cout << result[i] << " ";
	}
	cout << endl;
	system("pause");
}

运行结果:
在这里插入图片描述
关于

for (int i = 1; i < 10; i++) {     //得到每个数应该放入bucket中的位置
			count[i] += count[i - 1];
		}

的解释:
在这里插入图片描述
bucket数组的长度为11,那么按照个位取出的数字应该如何放入bucket中呢?
我们发现:{0, 100, 11, 32,123, 23, 564, 5, 56, 57, 169}
在这里插入图片描述
例如:169应该放入下标为10的位置上,100应该放在下标为1的位置上,32应该放在下标为3的位置上…计算规则为,要放到bucket中数的前面有多少个元素,那么他就要被放置到下标为几的位置上
在这里插入图片描述
所以要将数据累加,所以有了后边

for (int i = length - 1; i >= 0; i--) {  //采用倒序进行排序是为了不打乱已经排好的顺序
			int k = GetNum(input[i], d);
			bucket[count[k] - 1] = input[i];
			count[k]--;
		}

二、算法分析
1.时间复杂度
这个时间复杂度比较好计算:count * length;其中 count 为数组元素最高位数,length为元素个数;所以时间复杂度:O(n * d)
2.空间复杂度
空间复杂度是使用了两个临时的数组:10 + length;所以空间复杂度:O(n)

参考:
https://cuijiahua.com/blog/2018/01/algorithm_8.html
https://www.bilibili.com/video/BV1xz411i7Eb?from=search&seid=16588675175267367436

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值