基数排序

131 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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 + 基数

我们每次只需要将其放到桶中再取出,并不需要交换位置,所以该排序稳定