不得不知的排序八:基数排序

Posted 编程技术圈

tags:

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

8点20分,第一时间与你相约

每日英文 

If someone really wanted to be a part of your life, then he will be hard at it. 

如果某人真心想成为你生命中的一部分,那么他一定会为之努力。


每日掏心话 

有时,生活就是一种妥协,一种忍让,一种迁就。并不是所有的事情,都适宜针锋相对,铿锵有力,多彩的生活,既有阳光明媚,也有倾盆大雨。不要总是将你的东西为了某一个特别的时刻而预留着,因为你生活的每一天都是那么特别。


来自:静默虚空 | 责编:乐乐

链接:cnblogs.com/jingmoxukong/p/4311237.html

图片来自网络



  排序算法系列   




  01 要点   



基数排序与本系列前面讲解的七种排序方法都不同,它不需要比较关键字的大小

它是根据关键字中各位的值,通过对排序的N个元素进行若干趟“分配”与“收集”来实现排序的。

不妨通过一个具体的实例来展示一下,基数排序是如何进行的。

设有一个初始序列为: R {50, 123, 543, 187, 49, 30, 0, 2, 11, 100}。

我们知道,任何一个阿拉伯数,它的各个位数上的基数都是以0~9来表示的。

所以我们不妨把0~9视为10个桶。

我们先根据序列的个位数的数字来进行分类,将其分到指定的桶中。例如:R[0] = 50,个位数上是0,将这个数存入编号为0的桶中。

分类后,我们在从各个桶中,将这些数按照从编号0到编号9的顺序依次将所有数取出来。

这时,得到的序列就是个位数上呈递增趋势的序列。

按照个位数排序:{50, 30, 0, 100, 11, 2, 123, 543, 187, 49}。

接下来,可以对十位数、百位数也按照这种方法进行排序,最后就能得到排序完成的序列。


  02 算法分析   



基数排序的性能


不得不知的排序八:基数排序

时间复杂度

通过上文可知,假设在基数排序中,r为基数,d为位数。则基数排序的时间复杂度为O(d(n+r))

我们可以看出,基数排序的效率和初始序列是否有序没有关联。

空间复杂度

在基数排序过程中,对于任何位数上的基数进行“装桶”操作时,都需要n+r个临时空间。

算法稳定性

在基数排序过程中,每次都是将当前位数上相同数值的元素统一“装桶”,并不需要交换位置。所以基数排序是稳定的算法。


  03 3 完整参考代码   



LSD法实现

实现代码

package notes.javase.algorithm.sort;

public class RadixSort {

    // 获取x这个数的d位数上的数字
    // 比如获取123的1位数,结果返回3
    public int getDigit(int x, int d) {
        int a[] = {
                1110100
        }; // 本实例中的最大数是百位数,所以只要到100就可以了
        return ((x / a[d]) % 10);
    }

    public void radixSort(int[] listint begin, int end, int digit) {
        final int radix = 10// 基数
        int i = 0, j = 0;
        int[] count = new int[radix]; // 存放各个桶的数据统计个数
        int[] bucket = new int[end - begin + 1];

        // 按照从低位到高位的顺序执行排序过程
        for (int d = 1; d <= digit; d++) {

            // 置空各个桶的数据统计
            for (i = 0; i < radix; i++) {
                count[i] = 0;
            }

            // 统计各个桶将要装入的数据个数
            for (i = begin; i <= end; i++) {
                j = getDigit(list[i], d);
                count[j]++;
            }

            // count[i]表示第i个桶的右边界索引
            for (i = 1; i < radix; i++) {
                count[i] = count[i] + count[i - 1];
            }

            // 将数据依次装入桶中
            // 这里要从右向左扫描,保证排序稳定性
            for (i = end; i >= begin; i--) {
                j = getDigit(list[i], d); // 求出关键码的第k位的数字, 例如:576的第3位是5
                bucket[count[j] - 1] = list[i]; // 放入对应的桶中,count[j]-1是第j个桶的右边界索引
                count[j]--; // 对应桶的装入数据索引减一
            }

            // 将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表
            for (i = begin, j = 0; i <= end; i++, j++) {
                list[i] = bucket[j];
            }
        }
    }

    public int[] sort(int[] list) {
        radixSort(list0list.length - 13);
        return list;
    }

    // 打印完整序列
    public void printAll(int[] list) {
        for (int value : list) {
            System.out.print(value + "\t");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        int[] array = {
                5012354318749300211100
        };
        RadixSort radix = new RadixSort();
        System.out.print("排序前:\t\t");
        radix.printAll(array);
        radix.sort(array);
        System.out.print("排序后:\t\t");
        radix.printAll(array);
    }
}

运行结果

排序前: 50  123 543 187 49  30  0   2   11  100
排序后: 0   2   11  30  49  50  100 123 187 543 

不得不知的排序八:基数排序


这些排序算法你掌握了多少


欢迎在评论区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,或者在学习能力的提升上有新的认识,欢迎转发分享给更多人。



猜你还想看


                             
                               
                               
                             
关注「程序员小乐」,收看更多精彩内容

以上是关于不得不知的排序八:基数排序的主要内容,如果未能解决你的问题,请参考以下文章

不得不知的排序五:简单选择排序

你需要知道的九大排序算法Python实现之基数排序

不得不知的排序二:直接插入排序

不得不知的排序无:简单选择排序

不得不知的排序一:冒泡排序

不得不知的排序六:堆排序