引言
只要设计到数据,就会涉及到数据的排序问题,比如给你随机给你十个数 让你进行排序,那我们该怎样才是实现对这些整数的排序呢 ?
答案是多种多样的,比如用冒泡排序、希尔排序、计数排序、基数排序、快速排序等等,这些排序方法都可以实现对整数排序,而这篇文章要讲的就是基数排序
在学基数排序的时候,一定要先把计数排序学会,因为在代码中利用了计数排序的思想,如果计数排序不太理解,可以点击后面的链接,先把计数排序学会(重要)。 经典算法(八)----计数排序----图解法让你快速入门
本文将从以下几个问题对基数排序进行分析和讲解:
- 什么是基数排序?
- 基数排序的具体过程是什么?
- 基数排序的完整代码
- 基数排序的代码详解。
一、什么是基数排序
下面先看看百度百科对基数排序的定义:
基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法。
简单来说:比如我们要对13,52,72,65,54,90,25,44,75,81这十个数排序,那么利用基数排序,他的思想就是先按个位数的大小排(也可先按高位排序,这篇文章采取的是先按低位排序),再按十位排序。
- 先按个位排序,得到的是 90 81 52 72 13 54 44 65 25 75
- 再按十位排序,得到的是 13 25 44 52 54 65 72 75 81 90
因为上面的数最高位是十位,所以进行两边排序就可以了,因此在排序前,我们要求出这组数最大的位数。
其中每边排序采取的都是计数排序的方法,所以要提前学会计数排序,在学基数排序。
二、基数排序的具体过程是什么?
首先我们就是要求出要排序数组中最大数的位数。这个决定了要进行几次计数排序的过程
求解过程就是遍历数组,在这个过程中,对每个数的位数都求出来,去最大值即可,下面直接看代码(我相信你一定能看懂)
//统计数组中 最大数的位数 int max(int arr[],int len) { int maxn=0; for(int i=0;i<len;i++) { int count=0,data=arr[i]; while(data != 0) { count++; data/=10; } if(count>maxn) maxn=count; } return maxn; }
然后就可以开始遍历,第一次就是把每个数的个位数放到count数组里面。
如果对上面的count表有问题,为啥他要累加,这里累加的作用是解决排序的稳定性问题,如果对这排序的稳定性问题有疑问,那么你可以去看看这篇文章 ——> 经典算法(八)----计数排序----图解法让你快速入门
在计数排序文章中详细讲解了计数排序的实现过程,下面我们就需要利用计数排序的方法去学习基数排序。
一旦把数据放到了count数组之后,下面的过程就和计数排序一样了,我们直接放代码
//基数排序函数 稳定 void RadixSort(int arr[],int len) { int maxn=max(arr,len);//首先求出最大位数 int num=1;//求位数用 for(int k=0;k<maxn;k++)//根据位数,判断遍历几次 { int count[10]={0}; for(int i=0;i<len;i++)//把数据放入桶内 { int k=arr[i]/num%10; count[k]++; } //下面的过程都是计数排序的过程。 //根据计数排序,把桶内数据排序即可 for(int i=1;i<10;i++)//累加 { count[i]=count[i]+count[i-1]; } int temp[10]={0};//用来存放排序后的结果 for(int i=len-1;i>=0;i--)//逆序遍历,保证稳定性 { int ans=arr[i]/num%10; temp[count[ans]-1]=arr[i]; count[ans]--; } for(int i=0;i<len;i++) { arr[i]=temp[i]; } num*=10;//求更高位 } }
如果上面代码有些步骤不是很清楚 ,可以点击上面计数排序的链接。
三、基数排序的完整代码
下面看完整的代码
#include<iostream> using namespace std; //统计数组中 最大数的位数 int max(int arr[],int len) { int maxn=0; for(int i=0;i<len;i++) { int count=0,data=arr[i]; while(data) { count++; data/=10; } if(count>maxn) maxn=count; } return maxn; } //基数排序函数 稳定 void RadixSort(int arr[],int len) { int maxn=max(arr,len);//首先求出最大位数 int num=1;//求位数用 for(int k=0;k<maxn;k++)//根据位数,判断遍历几次 { int count[10]={0}; for(int i=0;i<len;i++)//把数据放入桶内 { int k=arr[i]/num%10; count[k]++; } //下面的过程都是计数排序的过程。 //根据计数排序,把桶内数据排序即可 for(int i=1;i<10;i++)//累加 { count[i]=count[i]+count[i-1]; } int temp[10]={0};//用来存放排序后的结果 for(int i=len-1;i>=0;i--)//逆序遍历,保证稳定性 { int ans=arr[i]/num%10; temp[count[ans]-1]=arr[i]; count[ans]--; } for(int i=0;i<len;i++) { arr[i]=temp[i]; } num*=10;//求更高位 } } //输出数组的值 void printf(int arr[],int len) { for(int i=0;i<len;i++) cout<<arr[i]<<" "; cout<<endl; } int main() { //要排序的数组 int arr[]={13,52,72,65,54,90,25,44,75,81}; int len=10;//要排序的数组长度 //排序 RadixSort(arr,len); //输出 printf(arr,len); return 0; }
运行结果:
四、基数排序的代码详解
- 学习这个基数排序,首先要知道基数排序的思想,知道它的大概过程是什么。
- 我认为最难的点就是把要排序的数组和count计数数组处理好,比如一开始count数组要存各个数的个位数,该怎样计数。等到逆序遍历(保证稳定性)的时候,怎样利用计数数组和要排序的数组,把每个数放到合适的位置上去。
本文参考以及引用: