图解基数排序,Java,C++代码

通俗理解

基数排序通俗点讲,就是先把所有待排序的元素按照个位数,十位数,百位数,…划分下去,先按照各个元素的个位数大小,对所有元素进行排序。基数排序是稳定的,也就是说要是同一位数上的数字相同,原先相对位置靠前的元素排位依旧相对靠前。当个位数排序结束后,再按照同样的方法依据更高位数字对元素进行排序,位数不足可看做补0。==排序趟数等于最大元素的位数。==所有位数都排序结束,得到的结果就是最终结果。

图码结合解释基数排序

十进制数基数排序可以理解为10个桶,用来表示10个基数

在这里插入图片描述

以数组nums = **[5, 8 , 11 , 1]**为例进行基数排序,对应10个桶需要一个长度为10的bucket数组,bucket数组是用来存放每一趟排序时各个桶存放的元素个数。再定义一个out数组来存放每一趟排序结束后的数组各元素情况。

int[] out = new int[nums.length];

在这里插入图片描述

排序过程

先取得数组中的最大值,初始进制设置为base = 1,每下一趟进制设置为base * 10。

long base = 1;  //使用long型是为了防止位数过长而整型溢出
int maxValue = Arrays.stream(nums).max().getAsInt();   //取得数组最大元素11
while(maxValue >= base) {    //确定排序趟数,最大排序趟数等于最大值的位数
    int[] bucket = new int[10];     //每一趟排序都把bucket重置为全0
    //其他代码
    base *= 10;
}

个位数排序

按照各个位数的数字对10取余决定当前元素应该放入哪一个桶里面。例如11和1的个位数都是1,所以个位数对10取余都是1,两者都应该放入1号桶里面,1号桶有两个元素,1号桶对应的bucket[1]应该为2。

for(int i = 0; i < nums.length; i++) {
	int digit = (nums[i] / (int)base) % 10;   //取得当前位数并决定元素应该放入哪一个桶
    bucket[digit] += 1;            //每一个桶的元素个数
}

在这里插入图片描述

将bucket数组各个位置的元素与前一位元素相加,目的是为了确定 i 号桶里面的元素在排序后的out数组中起始位置应该为多少(注意在排序数组里面下标应该减1)。比如相加后bucket[8] = 4,表明8号桶里面的元素8在排序后的out数组中是从第四个位置 (out数组对应的下标为3)开始存储的

for(int i = 1; i < 10; i++) {   //0号桶自然不用处理,因为按照bucket[0]等于多少开始排0号桶元素就可以了,而且0号桶元素位置就是其他桶的参考位置
    bucket[i] += bucket[i - 1];
}

在这里插入图片描述

接下来可以正向或者逆向将各个桶的元素取出来放到排序后的数组当中,注意基数排序是稳定的,所以如果是逆向拿桶的元素,下一个元素应该在上一个元素的前面。这里以逆序为例子。

for(int i = nums.lenth - 1; i >= 0; i--) {
    int digit = (nums[i] / (int)base) % 10;   //确定元素在几号桶
    out[bucket[digit] - 1] = nums[i];   //元素下标应该减1
    bucket[digit]--;         //每从桶里面排出一个元素,桶的元素就应该减1,同时也是对应排序数组的更左边的下标,保证了基数排序的稳定性
}

在这里插入图片描述

最后把整个排序数组复制到原数组,原数组就完成了个位数的排序。

System.arraycopy(out,0,nums,0,nums.length);

在这里插入图片描述

个位数排序结束后桶的情况依图所示。

在这里插入图片描述

十位数排序

依照个位数排序过程,十位数的1,5,8由于是为都是0,所以应该放到0号桶,0号桶有3个元素,一号桶有一个元素11。

在这里插入图片描述

十位数排序后,一号桶的元素在排序后的数组里面应该从第四个元素开始放置。

在这里插入图片描述

十位数排序后排序数组的结果应该如下。

在这里插入图片描述

十位数排序后的桶的结果如下图,由于最大值11只有两位数,所以两趟排序之后排序就结束了。

在这里插入图片描述

Java代码基数排序

public static void radixSort(int[] nums) {
    long base = 1;

    int[] out = new int[nums.length];
    int maxValue = Arrays.stream(nums).max().getAsInt();

    while(maxValue >= base) {
        int[] bucket = new int[10];
        for(int i = 0; i < nums.length; i++) {
            int digit = (nums[i] / (int)base) % 10;
            bucket[digit]++;
        }
        for(int i = 1; i < 10; i++) {
            bucket[i] += bucket[i - 1];
        }
        for(int i = nums.length - 1; i >= 0; i--) {
            int digit = (nums[i] / (int)base) % 10;
            out[bucket[digit] - 1] = nums[i];
            bucket[digit]--;
        }
        
        System.arraycopy(out,0,nums,0,nums.length);
        base *= 10;
   }
}

C++代码基数排序

class Sort {
public:
    int radixSort(vector<int>& nums) {
        int n = nums.size();
        int base = 1;
        vector<int> out(n);
        int maxValue = *max_element(nums.begin(),nums.end());
        
        while(maxValue >= base) {
            vector<int> bucket(10);
            for(int i = 0; i < n; i++) {
                int digit = (nums[i] / base) % 10;
                bucket[digit]++;
            }
            for(int i = 1; i < 10; i++) {
                bucket[i] += bucket[i - 1];
            }
            for(int i = n - 1; i >= 0; i--) {
                int digit = (nums[i] / base) % 10;
                out[bucket[digit] - 1] = nums[i];
                bucket[digit]--;
            }
            copy(out.begin(),out.end(),nums.begin());
            base *= 10;
        }
        
        return 0;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值