c++桶排序_带你快速了解基数排序的原理

8b77725434a82140d925df6e259fec30.png

之前的几篇文章已经给大家讲解了8种排序算法的原理以及C++代码实现方式,今天带大家快速了解一下基数排序算法。

9.基数排序(Radix Sort)

基数排序(radix sort)属于“分配式排序”(distribution sort),是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。基数排序法是属于稳定性的排序。

取得数组中的最大数,并取得位数;

arr为原始数组,从最低位开始取每个位组成radix数组;

对radix进行计数排序(利用计数排序适用于小范围数的特点);

9.2 动图演示

  • 先以个位数为基数进行入桶操作,然后再出桶,此时数据还是乱序的
  • 再以十位数为基数进行入桶操作,然后再出桶,此时数据已经排序完成
cd8933e748ded2c80ee5f74821ba8c7e.gif

代码实现:

//找出最大数,获得它的位数int getMaxBit(int arr[], int n) {int max = arr[0];for (int i = 1; i < n; i++){if (arr[i] > max)max = arr[i];}int bit = 1;while (max >= 10){max /= 10;bit++;}return bit;}void radixSort(int arr[], int n){int bit = getMaxBit(arr, n);int *tmp = new int[n];int *count = new int[10]; //计数器int i, j, k;int radix = 1;for (i = 1; i <= bit; i++) //进行bit次排序{//每次分配前清空计数器for (j = 0; j < 10; j++)count[j] = 0;//统计每个桶中的记录数for (j = 0; j < n; j++){k = (arr[j] / radix) % 10;count[k]++;}//记录每个基数的当前可用的第一个位置,比如基数为0的有2个,基数为1的有3个,则基数为0的第一个可用位置是0,基数为//1的第一个可用位置为2,因为前面已经有了两个基数为0的数,基数为1的第二个可用位置为3,以此类推int pos = count[0];int temp;for (j = 1; j < 10; j++){temp = count[j];count[j] = pos;pos += temp;}count[0] = 0;//将所有桶中记录依次收集到tmp中for (j = 0; j < n; j++){k = (arr[j] / radix) % 10; //计算arr[j]的基数tmp[count[k]] = arr[j]; //将arr[j]放入基数为k的第一个可用位置count[k]++; //基数为k的第一个可用位置往后移一位}//将临时数组的内容复制到arr中for (j = 0; j < n; j++)arr[j] = tmp[j];radix = radix * 10;}delete[]tmp;delete[]count;}

其中要注意更改count数组的这一段代码,是我自己喜欢这样写,我觉得更符合常规的思维:

25792cc5f9dba8574113125907762e9c.png
    //记录每个基数的当前可用的第一个位置,比如基数为0的有2个,基数为1的有3个,则基数为0的第一个可用位置是0,基数为//1的第一个可用位置为2,因为前面已经有了两个基数为0的数,基数为1的第二个可用位置为3,以此类推int pos = c[0];int temp;for (j = 1; j < 10; j++){temp = count[j];count[j] = pos;pos += temp;}count[0] = 0;//将所有桶中记录依次收集到tmp中for (j = 0; j < n; j++){k = (arr[j] / radix) % 10; //计算arr[j]的基数tmp[count[k]] = arr[j]; //将arr[j]放入基数为k的第一个可用位置count[k]++; //基数为k的第一个可用位置往后移一位}

通常的写法是如下这样的,大家可以对比一下这两种写法,选用自己更容易理解的实现方法。

c79cc03737d6ef4a322d8758ef7e5daa.png
for (i = 1; i < 10; i++)    count[i] += count[i - 1]; // 将数据存储到临时数组output[]中for (i = n - 1; i >= 0; i--){    k = (arr[j] / radix) % 10; //计算arr[j]的基数    tmp[count[k] - 1] = a[i];    count[k]--;}
aa69f814d988f5e65ebef960f5b4c8c9.png

基数排序的性能比桶排序要略差,每一次关键字的桶分配都需要O(n)的时间复杂度,而且分配之后得到新的关键字序列又需要m的时间复杂度,m为桶的个数。假如待排数据可以分为k个关键字,则基数排序的时间复杂度将是O(k*(n+m)) ,通常n>>m,因此基本上还是线性级别的。

基数排序的空间复杂度为O(n+m),其中m为桶的数量。通常n>>m,因此额外空间需要大概n个左右。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值