前言:
基数排序是一种有趣的排序算法,它稳定且时间复杂度为O(n)。效率挺高。我自己遇到了某个问题,顺手实现了一下它。我觉得这个排序方法蛮方便的,就是比较耗空间。
关于基数排序的解释与个人理解:
基数排序方法就是,将需要排序的数据从个位开始,依次到十位,百位,千位......进行排序。这个方法对数据的排序的规律体现出一种,迭代和逐渐规律化的样子来。也就是说,这个方法,对数据的一次处理是达不到有序化的。必须是对数据进行多次处理。
这种排序方法,其实是按照各个位上数字的大小进行排序的。首先,我们要确定数据中最大的数据的位数。较小的数据用0补充至与最大数据相同的位数。比如我们一组数据中存在3,而这组数据最大的数位10000,那么3将被扩充位00003。当然,我们实际上也不用去扩充,我们只需要知道在涉及到更高数位时,较小数据那个位置始终为0。就像取3的百位是0一样。
下面我将给出一个实际排序的例子,想信大家看后就明白了。
我们将对 1 23 50 20 100 5 9 110 10000 进行排序。
1.首先确定中间最大的数字为10000,那么对数据进行扩充后数组为:00001 00023 00050 00020 00100 00005 00009 00110 10000
2.按照上面数据个位上数据大小进行排序后的结果为:00050 00020 00100 00110 10000 00023 00005 00009
3.再对个位上排序后数据的结果再进行十位上数据大小排序后的结果为:00100 10000 00005 00009 00110 00020 00023 00050
4.再对百位上数据进行排序后结果为:10000 00005 00009 00020 00023 00050 00100 00110
5.再对千位上数据进行排序后结果为:10000 00005 00009 00020 00023 00050 00100 00110
6.再对万位上数据进行排序后结果为:00005 00009 00020 00023 00050 00100 00110 10000
7.最终排序结果为: 5 9 20 23 50 100 110 10000
相信大家看过这个例子后,便不难理解我所说的迭代,逐渐规律化的一种情况。其实基数排序排序的过程,就是一种划分的过程。只存在个位的数,与存在十位的数比起来,自然会排在更前面。最高位是十位的数,与存在百位的数比起来,自然也会在前面。以此类推。
关于基数排序如何取各个位置的数字:
我们可以用求模取余的方式进行求取。比如求个位上的数字时,只需要对数据对10取余。而取百位上数字时,就可以对数据对100取余,再对取余结果除10。千位上数字则是,对1000取余,除100.以此类推。这样运算,原本补充的0.也可以得到:
int t=nums[j]%mod;//mod为取余数
t=t/(mod/10);//当mol=100时,该运算为t=t/10,取百位数
关于基数排序过程中不断更新的数据状态的存储:
我们可以用一组数组来进行存储。声明10个数组。如果比较的位置是个位,且个位是0,则可以存入下标为0的数组中。若为1,则可存入下标为1的数组中。由于我们对数据是按照原来顺序由前到后进行操作,所以这样存储不会破坏原本该比较位上数字相同的数据之间的相对位置关系。这样分类后,我们只需要对这10个数组进行遍历,将数组中的数据重新装入原本存储数据的数组中即可。不过要记得将用过后的10个数组,清零。不要对后续操作产生影响。
我使用是c++中自带的vector动态数组进行存储。我简单的对其一些基本操作说明一下。
例如我们有个vector<int>mnm。我上面声明了一个动态数组mnm。
mnm.push_back(a)。就是将数据a加入动态数组末尾位置。
mnm.clear()即将动态数组中所有元素都删除。
下面我给出我进行状态转移的代码部分:
vector<long>mnm[10];
for(int i=1;i<=tot;i++){
for(int j=0;j<len;j++){
int t=nums[j]%mod;
t=t/(mod/10);
mnm[t].push_back(nums[j]);//将对应位置的数据加入数组中,比如0,加入nums[0]中
}
nums.clear();//清空nums
for(int j=0;j<=9;j++){
if(!mnm[j].empty()){
int le=mnm[j].end()-mnm[j].begin();//计算动态数组长度,当然也可以写
mnm[j].size()
for(int k=0;k<le;k++){
nums.push_back(mnm[j][k]);
}//将分类好的输入装回nums中
mnm[j].clear();//清空存储数组
}
}
mod*=10;//取下一位
}
一个应用实例:
给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。要求使用O(n)复杂度的排序算法
我也给出我的代码。当然,完全可以不按照我这样写,完成这个题
vector<int> sortedSquares(vector<int>& nums) {
//求平方
int len=nums.end()-nums.begin();
int maxx=0;
for(int i=0;i<len;i++){
nums[i]*=nums[i];
if(nums[i]>maxx){
maxx=nums[i];
}
}
//基数排序
int tot=0;
long mod=10;
while(maxx){
tot++;
maxx/=10;
}//统计最大基数的长度
vector<long>mnm[10];
for(int i=1;i<=tot;i++){
for(int j=0;j<len;j++){
int t=nums[j]%mod;
t=t/(mod/10);
mnm[t].push_back(nums[j]);
}
nums.clear();//清空nums
for(int j=0;j<=9;j++){
if(!mnm[j].empty()){
int le=mnm[j].end()-mnm[j].begin();
for(int k=0;k<le;k++){
nums.push_back(mnm[j][k]);
}
mnm[j].clear();//清空存储数组
}
}
mod*=10;//取下一位
}
return nums;
}
总结:
至于基数排序的算法实现,各有千秋。只要明白基数排序的思路,怎么写,不是基数排序啊。上面的程序只是按照我现在的习惯写的基数排序而已。