桶排序及基数排序(bucketSort and RadixSort)代码分析

桶排序(bucketSort)代码分析:
对于桶排序代码思路较为简单:
1. 求出数列中的最大值
2. 设计桶的数目等于最大值加一(因为是非负数数据,所以不存在无穷的情况,分析出最大值的情况下,数据最大能够达到的也就是max,最小为0)
3. 将整数数据放入到桶中,此时数据一旦放入到桶中一次,则桶的计数加一(记录着这个桶中一共有多少个数据)
4. 利用for循环将数据重新排列好赋值给arr,完成排序。

// only for 0~200 value
public static void bucketSort(int[] arr) {
    //排序中这个if都有,不多分析
    if (arr == null || arr.length < 2) {
        return;
    }
    //如果需要判断最大值,则先设目前最大值为系统最小值
    int max = Integer.MIN_VALUE;
    //一次遍历求出数组最大值
    for (int i = 0; i < arr.length; i++) {
        max = Math.max(max, arr[i]);
    }
    //求出数组最大之后开始新建桶
    int[] bucket = new int[max + 1];
    //将数组中的数据放入到桶中,并且将桶中的计数加一
    for (int i = 0; i < arr.length; i++) {
        bucket[arr[i]]++;
    }
    //下面这个for循环及i可以写成不一样的形式,但是总体没有区别,就不写了
    int i = 0;
    //将整个桶再遍历一遍
    for (int j = 0; j < bucket.length; j++) {
    	//如果此时桶中的数据大于0,则意味着桶中还保存着数据,执行循环操作
    	//如果此时桶中数据取完,则bucket[j]数据为0,退出循环
        while (bucket[j]-- > 0) {
            arr[i++] = j;
        }
    }
}

基数排序(radixSort)代码分析:
基数排序同样利用了桶排序,但是思路是完全不一样的,桶排序利用数据从高位开始每一位的大小来排序,如果在高位上数据不同,则可以直接从小到大排列,如果高位相同,则同样可以利用低位数据进行判断是否一致。
总体思路:
1. 首先求出最大数值是几位数(求出几位数之后方便之后进行几次的模10操作)
2. 将数组中数据每一位上进行比较,所以在每一位上设置十个桶,进行判断当前位上数据大小
2.1 进行判断的过程中,由于最高位有最高的话语权,所以我们从低到高进行运算,如果最高位比较大,则此时拥有绝对的话语权。
2.2 判断过程中,每一次循环当前位,都需要进行一次数据的排序,,所以需要求出当前数据应该排在整个数组中的位置。

// only for no-negative value
public static void radixSort(int[] arr) {
    if (arr == null || arr.length < 2) {
        return;
    }
    radixSort(arr, 0, arr.length - 1, maxbits(arr));
}
//算出来最大数是几位数
public static int maxbits(int[] arr) {
    int max = Integer.MIN_VALUE;
    for (int i = 0; i < arr.length; i++) {
        max = Math.max(max, arr[i]);
    }
    int res = 0;
    while (max != 0) {
        res++;
        max /= 10;
    }
    return res;
}
//进行整个排序操作
public static void radixSort(int[] arr, int begin, int end, int digit) {
    //数据如果从个位数来看,都属于0-9,所以总共是十个数,也就分为10个桶
    final int radix = 10;
    //此处仅仅是简化后面代码的书写,也可以不要
    int i = 0, j = 0;
    //可以将count理解为桶,用来保存数据在0-9上出现的次数
    int[] count = new int[radix];
    //bucket为最后保存数据的桶,他其实只有保存的操作,可以将count和bucket换一下命名会更加容易理解
    int[] bucket = new int[end - begin + 1];
    //digit为最大值所占的位数,下面的循环整体应该是在每一位上进行数据的比较,
    //从而得到整体的大小排序
    //从低位开始进行排序,如果当前位置小,则排在前面
    for (int d = 1; d <= digit; d++) {
        //首先将count都设为0,为了方便后面次数的加减
        for (i = 0; i < radix; i++) {
            count[i] = 0;
        }
        //将当前数据的倒数d位上的数据取出进行判断,进行桶排序
        for (i = begin; i <= end; i++) {
            j = getDigit(arr[i], d);
            count[j]++;
        }
        // 对于上面的count,将count数组中的个数求和,当前存储的个数为之前所有数目的总和。
        for (i = 1; i < radix; i++) {
            count[i] = count[i] + count[i - 1];
        }
        // 此时将数据从尾到头重新遍历一遍,j依旧为倒数第d位上的数据
        //这个函数的目的是将保存在count中的数目从小到大全部存放到桶bucket中
        for (i = end; i >= begin; i--) {
            j = getDigit(arr[i], d);
            //此时count中为所有数目的总和,所以此时count中的数据表示当前位数
            //从而可以利用这一点将这一位上数据相等的排好序保存到桶中
            bucket[count[j] - 1] = arr[i];
            //此时第count[j]位置上已经放了数,则此时开始让count[j]-1,这个位置就是当前位数相同,但之前位数较小的数据应该存放的位置
            count[j]--;
        }
        for (i = begin, j = 0; i <= end; i++, j++) {
            arr[i] = bucket[j];
        }
    }
}
//获取倒数第d项上的数值
public static int getDigit(int x, int d) {
    return ((x / ((int) Math.pow(10, d - 1))) % 10);
}

由于数据从最低位开始,所以从第一次最低位开始排序,进行下一次循环的时候,如果当前位置相等,则之前在数组中靠后的数据较大,排在前面位置的数据较小,在循环中可以发现是从后往前依次保存数据到bucket中的,则在满足当前数值排序的前提下,之前的顺序信息也保留了下来,实现了从最低位到最高位依次遍历从而实现整个数组的排序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值