008排序算法之基数排序

这篇文章你可以了解如下知识:

  • 你可以学习到基数的排序的思想
  • 可以学习用java实现基数排序
  • 主页也有全部的所有排序算法知识点,可以参考一下

系列文章

一、基本介绍

1、基本介绍

  • 基数排序(radix sort)属于“分配式排序”,又称为“桶子法”(bucket sort)或bin sort,顾名思义,它是通过键值的各个位的值,将要排序的元素分配致某些“桶”中,达到排序的作用。(说文字不太好理解,其实桶就是数组)
  • 基数排序法属于稳定的排序,基数排序法是效率高的稳定排序算法
  • 基数排序是桶排序的扩展
  • 基数排序是1887年赫尔曼.何乐礼发明的,它是这样实现的:将整数按位数切割成不同的数字,然后按每个位数分别比较。

2、基本思想

  • 将所有的待比较数值统一为同样的位数长度,数位较短的前面补0,然后从贵低位开始,依次进行排序,这样从低位排序一直到最高位排序完成以后,数列就变成一个有序序列。

3、来看一下图理解过程

  • 第一轮:现在是对个位排序
    在这里插入图片描述

  • 第二轮:现在是对十位进行排序。
    在这里插入图片描述- 第三轮:是对百位排序在这里插入图片描述

  • 总共重复多少轮呢:在于你的数据的位数大小

二、代码实现

每一句话都好好理解,包括每一句注释都好好理解,不然你很可能看不懂

(1)推导版

public class RadixSort {
    public static void main(String[] args) {
        int[] arr = {53,3,542,748,14,214};
        radixSort(arr);
        System.out.println(Arrays.toString(arr));
    }


    //基数排序方法
    public static void radixSort(int[] arr) {
        //推导版
        //先定义一个二维数组,代表10个桶,每一个桶就是一个一维数组
        //你无法判断你数里面究竟有1,2,3,4,5,6,7,8,9,0呢,不确定大小,只能多定义一点,显然就是空间换时间的经典算法
        int[][] bucket = new int[10][arr.length];

        //为了记录每一个桶中实际存放了多少个数据,因为我们不能判断,我们定义一个一维数组来记录各个桶放入数据的个数
        //bucketElementCounts[0]记录的就是bucket[0]的这个桶的数据个数
        int[] bucketElementCounts = new int[10];
        //第一轮,针对个位进行排序

        //1、把数据放入到对应的桶中
        for (int i = 0; i < arr.length; i++) {
            //取出每个元素的个位
            int digitOfELement = arr[i] % 10;
            //然后放到对应的桶中
                //bucketElementCounts[digitOfELement]这句话就得到了第多少个数据
            bucket[digitOfELement][bucketElementCounts[digitOfELement]] = arr[i];
            bucketElementCounts[digitOfELement] ++;//往后移动一个位置
        }
        //2、按照10个桶的顺序,把它取出放到原数组
        int index = 0;//用来索引我们的arr数组
        for (int i = 0; i < bucketElementCounts.length; i++) {
            //如果桶中有数据,我们才放入到原数组里面
            if (bucketElementCounts[i] != 0) {//说明对应的第k个桶有数据
                //循环第k个一维数组,放入原数组
                for (int j = 0; j < bucketElementCounts[i]; j++) {
                    //取出元素放入arr
                    arr[index] = bucket[i][j];
                    index++;
                }
            }
            //第一轮结束:要把我们的桶里面数据置零
            bucketElementCounts[i] = 0;
        }


        //第二轮的处理
        System.out.println("------------------------------------");
        //1、这个过程不用变化,除了一个%10
        for (int i = 0; i < arr.length; i++) {
            //取出每个元素的十位
            int digitOfELement = (arr[i] / 10) % 10;
            //然后放到对应的桶中
            //bucketElementCounts[digitOfELement]这句话就得到了第多少个数据
            bucket[digitOfELement][bucketElementCounts[digitOfELement]] = arr[i];
            bucketElementCounts[digitOfELement] ++;//往后移动一个位置
        }
        //2、放数据不变化
        index = 0;//用来索引我们的arr数组
        for (int i = 0; i < bucketElementCounts.length; i++) {
            //如果桶中有数据,我们才放入到原数组里面
            if (bucketElementCounts[i] != 0) {//说明对应的第k个桶有数据
                //循环第k个一维数组,放入原数组
                for (int j = 0; j < bucketElementCounts[i]; j++) {
                    //取出元素放入arr
                    arr[index] = bucket[i][j];
                    index++;
                }
            }
            //同样的道理
            bucketElementCounts[i] = 0;
        }


        //第三轮
        for (int i = 0; i < arr.length; i++) {
            //取出每个元素的百位
            int digitOfELement = (arr[i] / 100) % 10;
            //然后放到对应的桶中
            //bucketElementCounts[digitOfELement]这句话就得到了第多少个数据
            bucket[digitOfELement][bucketElementCounts[digitOfELement]] = arr[i];
            bucketElementCounts[digitOfELement] ++;//往后移动一个位置
        }
        //2、放数据完全不用变化
        index = 0;//用来索引我们的arr数组
        for (int i = 0; i < bucketElementCounts.length; i++) {
            //如果桶中有数据,我们才放入到原数组里面
            if (bucketElementCounts[i] != 0) {//说明对应的第k个桶有数据
                //循环第k个一维数组,放入原数组
                for (int j = 0; j < bucketElementCounts[i]; j++) {
                    //取出元素放入arr
                    arr[index] = bucket[i][j];
                    index++;
                }
            }
            //同样的道理
            bucketElementCounts[i] = 0;
        }
    }
}

(2)总体实现版

package cn.mldn;

import java.util.Arrays;

public class RadixSort {
    public static void main(String[] args) {
        int[] arr = {53,3,542,748,14,214};
        radixSort(arr);
        System.out.println(Arrays.toString(arr));
    }


    //基数排序方法
    public static void radixSort(int[] arr) {
        int[][] bucket = new int[10][arr.length];
        int[] bucketElementCounts = new int[10];




        //总体版
        //总的来说就要关心的是最大的位数,然后就没什么事了
        //所有我们要通过求解得到最大值,来判断到底要循环多少次

        //得到最大的数
        int max = arr[0];//假设最大值为arr[0]
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }

        //得到最大的位数,这个也很巧妙的
        int maxLength = (max + "").length();

        //这个n设置得很巧妙哦,一定以后要有这种思想,我们看看总体要实现多少次循环
        for (int y = 0, n = 1; y < maxLength; y++ , n = n * 10) {
            
            
            //1、把数据放入到对应的桶中
            for (int i = 0; i < arr.length; i++) {
                //取出每个元素的个位
                int digitOfELement = (arr[i] / n) % 10;
                //然后放到对应的桶中
                //bucketElementCounts[digitOfELement]这句话就得到了第多少个数据
                bucket[digitOfELement][bucketElementCounts[digitOfELement]] = arr[i];
                bucketElementCounts[digitOfELement] ++;//往后移动一个位置
            }
            //2、按照10个桶的顺序,把它取出放到原数组
            int index = 0;//用来索引我们的arr数组
            for (int i = 0; i < bucketElementCounts.length; i++) {
                //如果桶中有数据,我们才放入到原数组里面
                if (bucketElementCounts[i] != 0) {//说明对应的第k个桶有数据
                    //循环第k个一维数组,放入原数组
                    for (int j = 0; j < bucketElementCounts[i]; j++) {
                        //取出元素放入arr
                        arr[index] = bucket[i][j];
                        index++;
                    }
                }
                bucketElementCounts[i] = 0;
            }
        }

    }
}

(3)性能测试

看清楚啊,这里是八十万个数据哦,看性能都很高。比我们的快速排序都高,也一秒都用不了就OK了

package cn.mldn;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

public class RadixSort {
    public static void main(String[] args) {
        int[] arr = new int[800000];
        for (int i = 0; i < 800000; i++) {
            arr[i] = (int)(Math.random()*80000);//生成0到80000的数
        }
        //2、输出时间
        Date date1 = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd HH:mm:ss");//格式化
        String date1Str = simpleDateFormat.format(date1);
        System.out.println("排序前的时间" + date1Str);
        radixSort(arr);
        Date date2 = new Date();
        String date2Str = simpleDateFormat.format(date2);
        System.out.println("排序后的时间" + date2Str);
    }


    //基数排序方法
    public static void radixSort(int[] arr) {
        int[][] bucket = new int[10][arr.length];
        int[] bucketElementCounts = new int[10];




        //总体版
        //总的来说就要关心的是最大的位数,然后就没什么事了
        //所有我们要通过求解得到最大值,来判断到底要循环多少次

        //得到最大的数
        int max = arr[0];//假设最大值为arr[0]
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }

        //得到最大的位数,这个也很巧妙的
        int maxLength = (max + "").length();

        //这个n设置得很巧妙哦,一定以后要有这种思想,我们看看总体要实现多少次循环
        for (int y = 0, n = 1; y < maxLength; y++ , n = n * 10) {


            //1、把数据放入到对应的桶中
            for (int i = 0; i < arr.length; i++) {
                //取出每个元素的个位
                int digitOfELement = (arr[i] / n) % 10;
                //然后放到对应的桶中
                //bucketElementCounts[digitOfELement]这句话就得到了第多少个数据
                bucket[digitOfELement][bucketElementCounts[digitOfELement]] = arr[i];
                bucketElementCounts[digitOfELement] ++;//往后移动一个位置
            }
            //2、按照10个桶的顺序,把它取出放到原数组
            int index = 0;//用来索引我们的arr数组
            for (int i = 0; i < bucketElementCounts.length; i++) {
                //如果桶中有数据,我们才放入到原数组里面
                if (bucketElementCounts[i] != 0) {//说明对应的第k个桶有数据
                    //循环第k个一维数组,放入原数组
                    for (int j = 0; j < bucketElementCounts[i]; j++) {
                        //取出元素放入arr
                        arr[index] = bucket[i][j];
                        index++;
                    }
                }
                bucketElementCounts[i] = 0;
            }
        }

    }
}

(4)基数排序算法注意事项

基数排序是一个经典的空间换时间,你也可以测试一下,把我们的测试数据跳为八千万个数据,你的数据大了会浪费额外的内存,绝对会报错,除非你的内存很大,但是尽量不要太大。
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值