一篇文章弄懂——基数排序

基数排序(radix sort),相对于常见的比较排序,基数排序是一种分配式排序,即通过将所有数字分配到应在的位置最后再覆盖到原数组完成排序的过程。

基数排序思路

我们先给出一个待排序数组,和10个桶(桶从0开始编号)

我们需要依次将数组中取出来,分别放入10个桶中,入桶的规则:在第一回合中将数组元素按照个位上的值与“桶”号对应,进行入桶操作,例如:12,22,32,42,52这些都入2号桶。

第一步:将“17”入桶:

第二步:将“25入桶”

....将全部元素入桶后的效果:

当元素全部入桶后,就需要按照顺序依次出桶:从0号桶开始顺序出桶。

经过N步后,全部出桶的效果:

可以看到,经过第一回合的“分配”与“收集”操作后,数组的个位数已经有序了,此时我们需要对“十位”进行排序:我们按照每个数的“十位”对应桶号进行入桶操作,如果没有“十位”就按0计算:

入桶(分配)完后,我们就需要依次出桶:

此时经过两个回合的“分配”与“收集”操作后,数组元素就变得有序了,此时你已经走完了基数排序的全过程,仔细揣摩上面的步骤,你会发现,每一回合的“分配-收集”操作,就是对一个十进制位的排序。也就是假如数组中最大元素只有3位(例如:845),那么就只需要3个回合即可完成排序

代码实现

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        int[] arr = {17, 25, 12, 6, 24, 41, 1, 31, 30, 59};
        radixSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    /**
     * 对数组进行排序(基数排序)
     * @param arr
     */
    public static void radixSort(int[] arr) {
        int min = min(arr);
        int max = max(arr);
        int bits = bits(max);//获取数组中最大值的位数

        //初始化10个桶
        List<Integer>[] buckets = new List[10];
        for (int i = 0; i < buckets.length; i++) {
            buckets[i] = new ArrayList();
        }

        for (int i = 1; i <= bits; i++) {
            radixSort(arr, buckets, i);
        }
    }

    /**
     * 将数组arr,按照第n位来进行一次“分配”和“收集”操作
     *
     * @param arr
     * @param buckets 进行分配工作时用到的“桶”
     * @param n       按照第n位为基数进行排序
     */
    private static void radixSort(int[] arr, List<Integer>[] buckets, int n) {
        //进行“收集操作”
        for (int i = 0; i < arr.length; i++) {
            int bit = getBit(arr[i], n);
            buckets[bit].add(arr[i]);
        }

        int current = 0;
        //按顺序返回给原数组
        for (int i = 0; i < buckets.length; i++) {
            List<Integer> list = buckets[i];
            for (int j = 0; j < list.size(); j++) {
                arr[current] = list.get(j);
                current++;
            }
            list.clear();//清除桶中的元素
        }

    }

    /**
     * 获取某个值的第n位上的数,例如getBit(987,2)返回8
     *
     * @param value
     * @param n
     * @return
     */
    private static int getBit(int value, int n) {
        for (int i = 1; i < n; i++) {
            value /= 10;
        }
        return value % 10;
    }


    /**
     * 获得给定数组中的最大值
     *
     * @param arr
     * @return
     */
    private static int max(int[] arr) {
        int max = Integer.MIN_VALUE;
        for (int i : arr) {
            if (i > max) {
                max = i;
            }
        }
        return max;
    }

    /**
     * 获得数组中的最小值
     *
     * @param arr
     * @return
     */
    private static int min(int[] arr) {
        int min = Integer.MAX_VALUE;
        for (int i : arr) {
            if (i < min) {
                min = i;
            }
        }
        return min;
    }

    /**
     * 返回一个正整数的位数,例如100返回3  9999返回4
     *
     * @param value
     * @return
     */
    private static int bits(int value) {
        int bits = 0;
        while (value != 0) {
            bits++;
            value /= 10;
        }
        return bits;
    }
}

执行结果:

走到这里以为基数排序就学完了?NONONO,如果我们让数组中包含负数,你再试试结果:

你会惊奇的发现结果是错误的,实际上基数排序是不能处理含有负数的数组的。但是,我们在排序之前将数组全部加上一个常数,使其变成正数,然后排序完成后减去这个常数,不就可以完成负数的排序了吗!

代码改进

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        int[] arr = {-17, 25, 12, -6, 24, 41, 1, 31, 30, 59};
        radixSort(arr);
        System.out.println(Arrays.toString(arr));
    }

    public static void radixSort(int[] arr) {
        int min = min(arr);
        int tag = 0;
        if (min < 0) {//如果最小值小于零,那么需要给所有元素加上最小值的绝对值,因为基数排序实际上只能给正数排序
            tag -= min;
            for (int i = 0; i < arr.length; i++) {
                arr[i] += tag;
            }
        }
        int max = max(arr);
        int bits = bits(max);//获取数组中最大值的位数

        //初始化10个桶
        List<Integer>[] buckets = new List[10];
        for (int i = 0; i < buckets.length; i++) {
            buckets[i] = new ArrayList();
        }

        for (int i = 1; i <= bits; i++) {
            radixSort(arr, buckets, i);
        }
        if (min < 0) {
            for (int i = 0; i < arr.length; i++) {
                arr[i] -= tag;
            }
        }
    }

    /**
     * 将数组arr,按照第n位来进行一次“分配”和“收集”操作
     *
     * @param arr
     * @param buckets 进行分配工作时用到的“桶”
     * @param n       按照第n位为基数进行排序
     */
    private static void radixSort(int[] arr, List<Integer>[] buckets, int n) {
        //进行“收集操作”
        for (int i = 0; i < arr.length; i++) {
            int bit = getBit(arr[i], n);
            buckets[bit].add(arr[i]);
        }

        int current = 0;
        //按顺序返回给原数组
        for (int i = 0; i < buckets.length; i++) {
            List<Integer> list = buckets[i];
            for (int j = 0; j < list.size(); j++) {
                arr[current] = list.get(j);
                current++;
            }
            list.clear();//清除桶中的元素
        }

    }

    /**
     * 获取某个值的第n位上的数,例如getBit(987,2)返回8
     *
     * @param value
     * @param n
     * @return
     */
    private static int getBit(int value, int n) {
        for (int i = 1; i < n; i++) {
            value /= 10;
        }
        return value % 10;
    }


    /**
     * 获得给定数组中的最大值
     *
     * @param arr
     * @return
     */
    private static int max(int[] arr) {
        int max = Integer.MIN_VALUE;
        for (int i : arr) {
            if (i > max) {
                max = i;
            }
        }
        return max;
    }

    /**
     * 获得数组中的最小值
     *
     * @param arr
     * @return
     */
    private static int min(int[] arr) {
        int min = Integer.MAX_VALUE;
        for (int i : arr) {
            if (i < min) {
                min = i;
            }
        }
        return min;
    }

    /**
     * 返回一个正整数的位数,例如100返回3  9999返回4
     *
     * @param value
     * @return
     */
    private static int bits(int value) {
        int bits = 0;
        while (value != 0) {
            bits++;
            value /= 10;
        }
        return bits;
    }
}

完!!

 

原创不易,看客老爷们帮忙点个赞!!!

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

听到微笑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值