基数排序(数字排序和英文字母排序)

Posted Java编程生涯

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基数排序(数字排序和英文字母排序)相关的知识,希望对你有一定的参考价值。

一、算法介绍

基数排序属于“分配式排序”,又称桶子排序法,是一种稳定的排序算法。

基本操作:先找出数据最大的位数,然后按照从低位(从高位)开始排序,收集已排序的数据,直到最高位(最低位)排序完成。

例如:先个位排序,再十位排序,然后依次是百位、千位,直到最高位。

备注:基数排序有高位优先排序(简称MSD),和低位优先排序(简称LSD)两种排序方式。


二、算法原理

基数排序(数字排序和英文字母排序)

基础原理

第一步:先计算出数据的最大位数(最大长度)。

第二步:先从低位(高位)开始排序,收集已排序的数据,再从高位(低位)开始排序,收集已排序的数据。

第三步:不断从低位到高位(从高位到低位),对数据进行排序,直到最高位(最低位)已排好,排序完成。


算法步骤图解

LSD静态图:(先个位排序、再十位排序、再百位排序)

基数排序(数字排序和英文字母排序)


LSD动态图:(先个位排序、再十位排序、再百位排序)

基数排序(数字排序和英文字母排序)


算法复杂度:

最差情况:T(n) = O(n*k)

最好情况:T(n) = O(n*k)

当输入的元素是n 个0到k之间的整数时,它的运行时间是 O(n * k),其中k是整数的范围。


三、数字基数排序

基数排序(数字排序和英文字母排序)

数字基数排序原理

第一步:先计算出数据中数字的最大位数。

第二步:先从个位开始,根据个位数大小,把数据依次从小到大排序。

第三步:再从十位开始,根据十位数大小,把数据依次从小到大排序。 

第四步:再从百位、千位、计算对应位数的数据大小,一直到最高位的数据排序完成,才结束。


数字基数排序源码

/**
 * 数字基数排序
 * @param arr
 * @return
 */

public static int[] radixSort(int[] nums) {
    if(nums == null) {
        return null;
    }

    int digit = 0// 先默认只有0位
    int maxDigit = 0// 只记录最大的位数

    // 先获取数组的最大位数
    for (int i = 0; i < nums.length; i++) {
        int number = nums[i];
        while (number > 0) {
            number = number/10;

            digit++;
        }

        // 只记录最大的位数
        maxDigit = Math.max(maxDigit, digit);
        digit = 0// 初始化
    }

    ArrayList<ArrayList<Integer>> buckets = null;
    // 根据位数排序
    for (int i = 0; i < maxDigit; i++) {
        // 因为数字只有0到9总共10个,所以声明10个桶
        buckets = new ArrayList<ArrayList<Integer>>();
        for (int b = 0; b < 10; b++) {
            buckets.add(new ArrayList<Integer>());
        }

        // 排序,主要需要考虑到桶的容量,比如数组为10个桶,字母26个桶
        int base = (int) Math.pow(10, i);
        for (int a : nums) {
            int index = a / base % 10// 该步骤是为了获取最后一位数

            buckets.get(index).add(a); // 把最后一位一样的值分配到一个桶
        }

        int index = 0;
        for (ArrayList<Integer> bucket : buckets) {
            for (int b : bucket) {
                nums[index++] = b;
            }
        }
    }

    return nums;
}


四、英文字母排序

基数排序(数字排序和英文字母排序)

英文字母排序原理

第一步:先计算出数据中字符串最大长度。

第二步:从首字母开始排序,把字母转换成数字,相当于对数字进行排序。

第三步:继续下一个字母排序,直到最后一个字母排序完成。

备注:如果字符串超长,可能性能耗时会多一点。


英文字母排序源码

/**
 * 字符串基数排序
 * @param strArr
 * @return
 */

public static String[] stringRadixSort(String[] strArr) {
    if(strArr == null) {
        return null;
    }

    int maxLength = 0// 只记录最大的位数
    // 先获取数组的最大位数
    for (String len : strArr) {
        // 只记录最大的位数
        if (len.length() >= maxLength) {
            maxLength = len.length();
        }
    }
    System.out.println("字符串基数排序中字符串最大长度为: " + maxLength);

    ArrayList<ArrayList<String>> buckets = null;
    // 从最后一个字母开始排序
    for (int i=maxLength-1; i>=0; i--) {
        // 因为英文字母只有26个,所以声明26个桶
        buckets = new ArrayList<ArrayList<String>>();
        for (int b = 0; b < 27; b++) {
            buckets.add(new ArrayList<String>());
        }

        // 排序,主要需要考虑到桶的容量,比如数组为10个桶,字母26个桶
        for (String str : strArr) {
            buckets.get(getStrIndex(str, i)).add(str);
        }

        // 重新赋值
        int index = 0;
        for (ArrayList<String> bucket : buckets) {
            for (String str : bucket) {
                strArr[index++] = str;
            }
        }
    }

    return strArr;
}

public static int getStrIndex(String str, int charIndex) {    
    if (charIndex >= str.length()) {
        return 0// 第 0 个桶存非字母情况
    }       
    int index = 26// 总共26个字母
    int n = (int) str.charAt(charIndex); // 把字母强制转换成数字
    if (64 < n && n < 91) { // 大写字母区间范围
        index = n - 64;
    } else if (96 < n && n < 123) { // 小写字母区间范围
        index = n - 96;
    } else {
        // 把其余非字母的排最后
        index = 26;
    }
    return index;
}


学习要有三心,一信心,二决心,三恒心。

--陈景润

以上是关于基数排序(数字排序和英文字母排序)的主要内容,如果未能解决你的问题,请参考以下文章

算法基数排序

20191209-八大排序之基数排序

从左到右基数排序

如何对包含多个字符串的结构应用基数排序(使用计数排序)

基数排序不排序“一些”数字?

基数排序和更改基数