持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第18天
基数排序
要实现基数排序,我们需要准备两个桶,一个大桶,十个小桶,十个小桶分别标号0-9,一股脑放在这个大桶中,在代码中表示出来,就是我们的二维数组,arr[[],[],[],[],[],[],[],[],[],[]],再准备一个待排序的数组,我们就准备好了排序前的物质基础
思想
我们拿到待排序的数组[2, 3, 4, 201, 27001, 132],先以其内所有元素的个位数为标准做个排序:
得到[201, 27001, 2, 132, 3, 4](加黑的为排序依据)
你现在可能会觉得很奇怪:这是要做什么?且不要急,和我向下一起看
以每个元素的个位为标准的排序完毕,接下来我们以元素的十位为标准进行排序:
得到[201, 27001, 02, 03, 04, 132](加黑的为排序依据)
下面,我们再进行第三轮:按照百位排序
得到[27001, 002, 003, 004, 132, 201]
不用多说,第四轮:按千位排
得到[0002, 0003, 0004, 0132, 0201, 27001]
27001还有一位万位元素没有排序,但现在数组已经有序,我们就不继续下去,在代码实现中,我们就按照这样的思路进行排序,每次将对应的位数依次放到对应的桶中:比如第一轮按个位排序,先将 2 放到对应2标号的小桶中,将3放到对应3标号的小桶中,就这样直到最后一个元素132放到2标号对应的桶中,就初步得到了完整的桶:
[ [ 201, 27001 ], [ 2, 132 ], [ 3 ], [ 4 ] ](一些空桶就不进行初始化了,这里只展示有元素的桶)
我们现在将其有序放入原始数组中,先从序号小的桶开始往出抽,先抽出201, 27001,再抽出2, 132,依次填入原始数组中,覆盖掉原数据:
[201, 27001, 2, 132, 3, 4]
就按这样的思路,再进行十位和百位以及后续位数的排序,最后就能得到有序的数组,原理根据思想表现来看也不难明白。
实现(javascript)
function redixSort(arr){
//定义大桶,里面用来放对应位数排序的一个个小桶,以二维的形式存储
let sortArr = [];
//获取数组中的最大位数
let Maxpos = getMaxPos(arr);
//外层for按位数循环,有三位就循环三次,分别按个、十、百位遍历
for(let i = 0;i < Maxpos;i++){
//内层第一个for将元素拆分,一个个放到小桶里
for(let j = 0;j < arr.length;j++){
//取出当前遍历数组元素的对应位数
let posEle = parseInt((arr[j]/10**i)%10);
//如果大桶内还没有对应位数的小桶,就初始化一个小桶出来
if(sortArr[posEle] === undefined){
sortArr[posEle] = [];
}
//将当前遍历的数组元素存入对应位数的小桶中
sortArr[posEle].push(arr[j]);
}
let pos = 0;//为下面将小捅内容放入总数组中做下标指针
//内层第二个for按0-9的顺序遍历小桶,将所有元素再次穿起来,放回arr中
for(let j = 0;j < sortArr.length;j++){
console.log(sortArr);
while(sortArr[j] != undefined &&sortArr[j].length != 0){
//将小桶中第一个元素放在大桶最后一个位置中
arr[pos++] = sortArr[j].shift();
}
}
}
return arr;
}
/**
* 获取数组中的最大位数
* @param {*} arr
*/
function getMaxPos(arr){
let max = 0;
for(let item of arr){
if(max < item){
max = item;
}
}
let pos = 0
for( ;max > 1;pos++){
max /= 10;
}
return pos;
}
时空复杂度及稳定性
基数排序的时间复杂度为O(最大位数 * (n + 基数,也就是大桶中元素的个数))
基数排序的效率和初始序列是否有序没有关联
我们用到了n+基数个额外空间,所以空间复杂度就为 n + 基数
我们每次只需要将其放到桶中再取出,并不需要交换位置,所以该排序稳定