精华内容
下载资源
问答
  • 基数排序基数排序基数排序基数排序基数排序
  • 基数排序

    2019-10-27 21:12:32
    基数排序一、什么是基数排序二、基数排序的代码实现三、总结 一、什么是基数排序 基数排序属于非比较类排序——非比较类排序包括计数排序、基数排序、桶排序。 基数排序是由计数排序改善而来的,基数排序将整数或者...

    一、什么是基数排序

    基数排序属于非比较类排序——非比较类排序包括计数排序、基数排序、桶排序。
    在这里插入图片描述

    基数排序是由计数排序改善而来的,基数排序将整数或者字符串切分不同的数字或字符,然后按照低位先排序收集,接着高位排序收集,依次类推直到最高位。

    动图演示
    在这里插入图片描述

    二、基数排序的代码实现

    public static void sort(int[] arr){
        int length = arr.length;
    
        //最大值
        int max = arr[0];
        for(int i = 0;i < length;i++){
            if(arr[i] > max){
                max = arr[i];
            }
        }
        //当前排序位置
        int location = 1;
    
        //桶列表
        ArrayList<ArrayList<Integer>> bucketList = new ArrayList<>();
    
        //长度为10 装入余数0-9的数据
        for(int i = 0; i < 10; i++){
            bucketList.add(new ArrayList());
        }
    
        while(true)
        {
            //判断是否排完
            int dd = (int)Math.pow(10(location - 1));
            if(max < dd){
                break;
            }
    
            //数据入桶
            for(int i = 0; i < length; i++)
            {
                //计算余数 放入相应的桶
                int number = ((arr[i] / dd) % 10);
                bucketList.get(number).add(arr[i]);
            }
    
            //写回数组
            int nn = 0;
            for (int i=0;i<10;i++){
                int size = bucketList.get(i).size();
                for(int ii = 0;ii < size;ii ++){
                    arr[nn++] = bucketList.get(i).get(ii);
                }
                bucketList.get(i).clear();
            }
            location++;
        }
    }
    

    三、总结

    基数排序是稳定的算法,算法的时间复杂度为O(d(n+r)),d为位数,r为基数。算法这块考察的最基础的知识就是排序这一块了,实际有十大排序算法,但我认为只要掌握八大排序算法就已经够了。其实在很多时候,程序员对于排序算法应该算是非常熟悉了,有些语言例如c++STL容器也封了排序算法。但这些还不够,对自己的最低要求是要能手写这些算法的实现,清楚每种算法的特性、时间复杂度等。

    展开全文
  • 排序算法 基数排序

    万次阅读 2019-10-20 22:39:23
    又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度O (nlog(r)m),其中r所采取...

    一、基数排序

    1、介绍。

            基数排序(radix sort)属于“分配式排序”(distribution sort),又称“桶子法”(bucket sort)或bin sort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O (nlog(r)m),其中r为所采取的基数,而m为堆数,在某些时候,基数排序法的效率高于其它的稳定性排序法

            基数排序是稳定排序,需要额外内存,空间复杂度O(n*k)。时间复杂度,最佳情况:O(n*k)  最差情况:O(n*k)  平均情况:O(n*k)。

    2、步骤。

        (1)第一趟桶排序将数字的个位数分配到桶子里面去,然后回收起来,此时数组元素的所有个位数都已经排好顺序了
        (2)第二趟桶排序将数字的十位数分别分配到桶子里面去,然后回收起来,此时数组元素的所有个位数和十位数都已经排好顺序了(如果没有十位数、则补0)
        (3)第三趟桶排序将数字的百位数分别分配到桶子里面去,然后回收起来,此时数组元素的所有个位数和十位数和百位数都已经排好顺序了(如果没有百位数、则补0)
        (4)直至全部数(个、十、百、千位...)排好顺序,那么这个数组就是有序的了。

    3、代码。

    static class Bucket { //跟main方法在同个类里面
        public int value = -1;
        public Bucket next;//下一次Bucket
        public Bucket last;//最后一个Bucket
    }
    public static void main(String[] args) {
            System.out.println("------开始------");
            //生成生成两份一模一样的随机数组,其中一组用系统自带的方法进行排序,到时候进行验证。
            final int number = 100000;//100000
            int[] sortArray = new int[number];
            int[] sortArrayCopy = new int[number];
            for (int i = 0; i < sortArray.length; i++) {
                sortArray[i] = (int) (Math.random() * number);
            }
            System.arraycopy(sortArray, 0, sortArrayCopy, 0, number);//数组复制
            Arrays.sort(sortArrayCopy);
    
            //开始排序
            long startTime = System.currentTimeMillis();
            radixSort(sortArray);//基数排序
            System.out.println("花费时间:" + (System.currentTimeMillis() - startTime));
    
            //跟系统排序之后数组进行比较,查看是否排序成功。
            if (Arrays.equals(sortArray, sortArrayCopy)) {
                System.out.println("排序成功");
            } else {
                System.out.println("排序失败");
            }
            System.out.println("------结束------");
        }
    private static void radixSort(int[] array) {
        //找出array的最大值
        int max = array[0], min = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        //算出最大值的位数
        int maxDigit = 0;
        while (max != 0) {
            max /= 10;
            maxDigit++;
        }
        int mod = 10, div = 1;
        //
        for (int i = 0; i < maxDigit; i++, mod *= 10, div *= 10) {
            //初始化
            Bucket[] bucketArray = new Bucket[10];
            for (int k = 0; k < bucketArray.length; k++) {
                bucketArray[k] = new Bucket();
                bucketArray[k].last = bucketArray[k];//默认链表尾为自己
            }
            //装入bucketArray中
            for (int j = 0; j < array.length; j++) {
                int num = (array[j] % mod) / div;
                //从链表的表尾插入
                Bucket bucket = new Bucket();
                bucket.value = array[j];
                bucketArray[num].last.next = bucket;//bucket接在链表尾
                bucketArray[num].last=bucket;//bucket变成链表尾
            }
            //从bucketArray中取值,对重新排序
            int index = 0;
            for (int j = 0; j < bucketArray.length; j++) {
                Bucket pre = bucketArray[j];//上一个
                while (pre.next != null) {
                    Bucket now = pre.next;
                    array[index++] = now.value;
                    pre = now;
                }
            }
        }
    }

    4.结果。

    展开全文
  • 排序算法系列:基数排序

    万次阅读 多人点赞 2016-06-16 23:14:07
    这也是基数排序的魅力所在,基数排序可以理解成是建立在“计数排序”的基础之上的一种排序算法。在实际项目中,如果对效率有所要求,而不太关心空间的使用时,我会选择用计数排序(当然还有一些其他的条件),或是...

    引言

    今天要说的这个排序算法很特殊,它不需要直接对元素进行相互比较,也不需要将元素相互交换,你需要做的就是对元素进行“分类”。这也是基数排序的魅力所在,基数排序可以理解成是建立在“计数排序”的基础之上的一种排序算法。在实际项目中,如果对效率有所要求,而不太关心空间的使用时,我会选择用计数排序(当然还有一些其他的条件),或是一些计数排序的变形。


    版权说明

    著作权归作者所有。
    商业转载请联系作者获得授权,非商业转载请注明出处。
    本文作者:Q-WHai
    发表日期: 2016年6月16日
    本文链接:https://qwhai.blog.csdn.net/article/details/51695211
    来源:CSDN
    更多内容:分类 >> 算法与数学


    基数排序

    数据背景

    在基数排序中,我们不能再只用一位数的序列来列举示例了。一位数的序列对基数排序来说就是一个计数排序。
    这里我们列举无序序列 T = [ 2314, 5428, 373, 2222, 17 ]

    排序原理

    上面说到基数排序不需要进行元素的比较与交换。如果你有一些算法的功底,或者丰富的项目经验,我想你可能已经想到了这可能类似于一些“打表”或是哈希的做法。而计数排序则是打表或是哈希思想最简单的实现。

    计数排序

    计数排序的核心思想是,构建一个足够大的数组 hashArray[],数组大小需要保证能够把所有元素都包含在这个数组上 。
    假设我们有无序序列 T = [ 2314, 5428, 373, 2222, 17 ]
    首先初始化数组 hashArray[] 为一个全零数组。当然,在 Java 里,这一步就不需要了,因为默认就是零了。
    在对序列 T 进行排序时,只要依次读取序列 T 中的元素,并修改数组 hashArray[] 中把元素值对应位置上的值即可。这一句有一些绕口。打个比方,我们要把 T[0] 映射到 hashArray[] 中,就是 hashArray[T[0]] = 1. 也就是 hashArray[2314] = 1. 如果序列 T 中有两个相同元素,那么在 hashArray 的相应位置上的值就是 2。
    下图是计数排序的原理图:
    (假设有无序序列:[ 5, 8, 9, 1, 4, 2, 9, 3, 7, 1, 8, 6, 2, 3, 4, 0, 8 ])
    20160616230144072

    基数排序原理图

    上面的计数排序只是一个引导,好让你可以循序渐进地了解基数排序。
    20160616230403191

    上面这幅图,或许你已经在其他的博客里见到过。这是一个很好的引导跟说明。在基数排序里,我们需要一个很大的二维数组,二维数组的大小是 (10 * n)。10 代表的是我们每个元素的每一位都有 10 种可能,也就是 10 进制数。在上图中,我们是以每个数的个位来代表这个数,于是,5428 就被填充到了第 8 个桶中了。下次再进行填充的时候,就是以十位进行填充,比如 5428 在此时,就会选择以 2 来代表它。
    20160616230636486

    算法优化

    在算法的原理中,我们是以一张二维数组的表来存储这些无序的元素。使用二维数组有一个很明显的不足就是二维数组太过稀疏。数组的利用率为 10%。
    在寻求优化的路上,我们想到一种可以压缩空间的方法,且时间复杂度并没有偏离得太厉害。那就是设计了两个辅助数组,一个是 count[],一个是 bucket[]。count 用于记录在某个桶中的最后一个元素的下标,然后再把原数组中的元素计算一下它应该属于哪个“桶”,并修改相应位置的 count 值。直到最大数的最高位也被添加到桶中,或者说,当所有的元素都被被在第 0 个桶中,基数排序就结束了。
    优化后的原理图如下:
    20160616230836459

    算法实现

    import org.algorithm.array.sort.interf.Sortable;
    
    /**
     * <p>
     * 基数排序/桶排序
     * </p>
     * 2016年1月19日
     * 
     * @author <a href="http://weibo.com/u/5131020927">Q-WHai</a>
     * @see <a href="http://blog.csdn.net/lemon_tree12138">http://blog.csdn.net/lemon_tree12138</a>
     * @version 0.1.1
     */
    public class RadixSort implements Sortable {
        
        @Override
        public int[] sort(int[] array) {
            if (array == null) {
                return null;
            }
            
            int maxLength = maxLength(array);
            
            return sortCore(array, 0, maxLength);
        }
    
        private int[] sortCore(int[] array, int digit, int maxLength) {
            if (digit >= maxLength) {
                return array;
            }
            
            final int radix = 10; // 基数
            int arrayLength = array.length;
            int[] count = new int[radix];
            int[] bucket = new int[arrayLength];
            
            // 统计将数组中的数字分配到桶中后,各个桶中的数字个数
            for (int i = 0; i < arrayLength; i++) {
                count[getDigit(array[i], digit)]++;
            }
            
            // 将各个桶中的数字个数,转化成各个桶中最后一个数字的下标索引
            for (int i = 1; i < radix; i++) {
                count[i] = count[i] + count[i - 1];
            }
            
            // 将原数组中的数字分配给辅助数组 bucket
            for (int i = arrayLength - 1; i >= 0; i--) {
                int number = array[i];
                int d = getDigit(number, digit);
                bucket[count[d] - 1] = number;
                count[d]--;
            }
            
            return sortCore(bucket, digit + 1, maxLength);
        }
        
        /*
         * 一个数组中最大数字的位数
         * 
         * @param array
         * @return
         */
        private int maxLength(int[] array) {
            int maxLength = 0;
            int arrayLength = array.length;
            for (int i = 0; i < arrayLength; i++) {
                int currentLength = length(array[i]);
                if (maxLength < currentLength) {
                    maxLength = currentLength;
                }
            }
            
            return maxLength;
        }
        
        /*
         * 计算一个数字共有多少位
         * 
         * @param number
         * @return
         */
        private int length(int number) {
            return String.valueOf(number).length();
        }
        
        /*
         * 获取 x 这个数的 d 位数上的数字
         * 比如获取 123 的 0 位数,结果返回 3
         * 
         * @param x
         * @param d
         * @return
         */
        private int getDigit(int x, int d) {
            int a[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
            return ((x / a[d]) % 10);
        }
    }
    

    基数排序过程图

    如果我们的无序是 T = [ 2314, 5428, 373, 2222, 17 ],那么其排序的过程就如下两幅所示。
    基数排序过程图-1
    20160616230950318

    基数排序过程图-2
    20160616231008959

    复杂度分析

    排序方法 时间复杂度 空间复杂度 稳定性 复杂性
    平均情况 最坏情况 最好情况
    基数排序 O(d*(n+r)) O(d*(n+r)) O(d*(n+r)) O(n+r) 稳定 较复杂
    其中,d 为位数,r 为基数,n 为原数组个数。 在基数排序中,因为没有比较操作,所以在复杂上,最好的情况与最坏的情况在时间上是一致的,均为 O(d * (n + r))。

    Ref

    • 《算法导论》

    GitHub Download

    • https://github.com/qwhai/algorithms-sort

    征集

    如果你也需要使用ProcessOn这款在线绘图工具,可以使用如下邀请链接进行注册:
    https://www.processon.com/i/56205c2ee4b0f6ed10838a6d

    展开全文

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 68,640
精华内容 27,456
关键字:

以3为基数的基数排序