java数据结构和算法——基数排序算法

目录

    • 一、基数排序算法的(桶排序)介绍
    • 二、基数排序算法的基本思想
    • 三、基数排序算法的思路分析图解
    • 四、基数排序算法的应用示例需求
    • 五、基数排序算法的推导过程示例演示
    • 六、基数排序算法的完整示例演示
    • 七、测试基数排序算法所消耗的时间示例
    • 八、基数排序存算法注意事项

一、基数排序算法的(桶排序)介绍

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

二、基数排序算法的基本思想

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

三、基数排序算法的思路分析图解

java数据结构和算法——基数排序算法_第1张图片java数据结构和算法——基数排序算法_第2张图片

四、基数排序算法的应用示例需求

将数组 {53, 3, 542, 748, 14, 214 } 使用基数排序, 进行升序排序

五、基数排序算法的推导过程示例演示

1、代码

package com.rf.springboot01.dataStructure.sort;

import java.util.Arrays;

/**
 * @description: 基数排序算法的推导过程示例演示
 * @author: xiaozhi
 * @create: 2020-08-12 22:23
 */
public class RadixSort {
    public static void main(String[] args) {
        int arr[] = { 53, 3, 542, 748, 14, 214};
        radixSort(arr);
    }
    
    /** 
    * @Description:  基数排序算法的推导过程示例方法
    * @Param: [arr] 
    * @Author: xz  
    * @return: void
    * @Date: 2020/8/12 22:25  
    */ 
    public static void radixSort(int[] arr){

        //定义一个二维数组,表示10个桶, 每个桶就是一个一维数组
        //说明
        //1. 二维数组包含10个一维数组
        //2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arr.length
        //3. 很明确的表示,基数排序是使用空间换时间的经典算法
        int[][] bucket=new int[10][arr.length];

        //为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数
        //可以这么理解 比如:bucketElementCounts[0] , 记录的就是  bucket[0] 桶的放入数据个数
        int[] bucketElementCounts=new int[10];
        
        /** 
        * @Description: 第一轮(针对每个元素的个位数进行排序处理)
        * @Param: [arr] 
        * @Author: xz  
        * @return: void
        * @Date: 2020/8/12 22:29  
        */
        for(int j=0;j<arr.length;j++){
            //取出每个元素的个位的值
            int digitElement=arr[j]/1%10;
            //放入到对应的桶中
            //1、bucket[digitElement] 表示个位数对应的第个位数的桶
            //2、bucketElementCounts[digitElement] 表示个位数对应的第个位数的桶的数据个数
            bucket[digitElement][bucketElementCounts[digitElement]]=arr[j];
            bucketElementCounts[digitElement]++;
        }

        //按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
        //遍历每一桶,并将桶中是数据,放入到原数组
        int index=0;
        for(int k = 0 ; k < bucket.length ; k++){
            //如果桶中有数据,我们才放入到原数组
            if( bucketElementCounts[k] !=0){
                //循环该桶即第k个桶(即第k个一维数组), 放入
                for(int m=0;m<bucketElementCounts[k];m++){
                    //取出元素放入到arr
                    arr[index]=bucket[k][m];
                    index++;
                }
            }
            //第一轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!
            bucketElementCounts[k] = 0;
        }
        System.out.println("第1轮,对个位的排序处理 arr =" + Arrays.toString(arr));


        /**
         * @Description: 第二轮(针对每个元素的十位数进行排序处理)
         * @Param: [arr]
         * @Author: xz
         * @return: void
         * @Date: 2020/8/12 22:29
         */
        for(int j=0;j<arr.length;j++){
            //取出每个元素的个位的值
            int digitElement=arr[j]/10%10;
            //放入到对应的桶中
            //1、bucket[digitElement] 表示个位数对应的第个位数的桶
            //2、bucketElementCounts[digitElement] 表示个位数对应的第个位数的桶的数据个数
            bucket[digitElement][bucketElementCounts[digitElement]]=arr[j];
            bucketElementCounts[digitElement]++;
        }

        //按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
        //遍历每一桶,并将桶中是数据,放入到原数组
        index=0;
        for(int k = 0 ; k < bucket.length ; k++){
            //如果桶中有数据,我们才放入到原数组
            if( bucketElementCounts[k] !=0){
                //循环该桶即第k个桶(即第k个一维数组), 放入
                for(int m=0;m<bucketElementCounts[k];m++){
                    //取出元素放入到arr
                    arr[index]=bucket[k][m];
                    index++;
                }
            }
            //第二轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!
            bucketElementCounts[k] = 0;
        }
        System.out.println("第2轮,对十位的排序处理 arr =" + Arrays.toString(arr));

        /**
         * @Description: 第三轮(针对每个元素的百位数进行排序处理)
         * @Param: [arr]
         * @Author: xz
         * @return: void
         * @Date: 2020/8/12 22:29
         */
        for(int j=0;j<arr.length;j++){
            //取出每个元素的个位的值
            int digitElement=arr[j]/100%10;
            //放入到对应的桶中
            //1、bucket[digitElement] 表示个位数对应的第个位数的桶
            //2、bucketElementCounts[digitElement] 表示个位数对应的第个位数的桶的数据个数
            bucket[digitElement][bucketElementCounts[digitElement]]=arr[j];
            bucketElementCounts[digitElement]++;
        }

        //按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
        //遍历每一桶,并将桶中是数据,放入到原数组
        index=0;
        for(int k = 0 ; k < bucket.length ; k++){
            //如果桶中有数据,我们才放入到原数组
            if( bucketElementCounts[k] !=0){
                //循环该桶即第k个桶(即第k个一维数组), 放入
                for(int m=0;m<bucketElementCounts[k];m++){
                    //取出元素放入到arr
                    arr[index]=bucket[k][m];
                    index++;
                }
            }
            //第三轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!
            bucketElementCounts[k] = 0;
        }
        System.out.println("第3轮,对百位的排序处理 arr =" + Arrays.toString(arr));
    }

}

2、运行main函数,运行结果如下:
java数据结构和算法——基数排序算法_第3张图片

六、基数排序算法的完整示例演示

1、代码

package com.rf.springboot01.dataStructure.sort;

import java.util.Arrays;

/**
 * @description: 基数排序算法的完整示例演示
 * @author: xiaozhi
 * @create: 2020-08-12 22:49
 */
public class RadixSort2 {
    public static void main(String[] args) {
        int arr[] = { 53, 3, 542, 748, 14, 214};
        radixSort(arr);
    }

    /**
     * @Description:  基数排序算法的推导过程示例方法
     * @Param: [arr]
     * @Author: xz
     * @return: void
     * @Date: 2020/8/12 22:25
     */
    public static void radixSort(int[] arr) {

        //定义一个二维数组,表示10个桶, 每个桶就是一个一维数组
        //说明
        //1. 二维数组包含10个一维数组
        //2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arr.length
        //3. 很明确的表示,基数排序是使用空间换时间的经典算法
        int[][] bucket = new int[10][arr.length];

        //为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数
        //可以这么理解 比如:bucketElementCounts[0] , 记录的就是  bucket[0] 桶的放入数据个数
        int[] bucketElementCounts = new int[10];

        //1. 得到数组中最大的数的位数
        int max = arr[0]; //假设第一数就是最大数
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        //得到最大数是几位数
        int maxLength = (max + "").length();
        /**
         * @Description: 针对每个元素的个位数进行排序处理
         * @Param: [arr]
         * @Author: xz
         * @return: void
         * @Date: 2020/8/12 22:29
         */
        for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
            //(针对每个元素的对应位数进行排序处理), 第一次是个位,第二次是十位,第三次是百位..
            for (int j = 0; j < arr.length; j++) {
                //取出每个元素的个位的值
                int digitElement = arr[j] / n % 10;
                //放入到对应的桶中
                //1、bucket[digitElement] 表示个位数对应的第个位数的桶
                //2、bucketElementCounts[digitElement] 表示个位数对应的第个位数的桶的数据个数
                bucket[digitElement][bucketElementCounts[digitElement]] = arr[j];
                bucketElementCounts[digitElement]++;
            }

            //按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
            //遍历每一桶,并将桶中是数据,放入到原数组
            int index = 0;
            for (int k = 0; k < bucket.length; k++) {
                //如果桶中有数据,我们才放入到原数组
                if (bucketElementCounts[k] != 0) {
                    //循环该桶即第k个桶(即第k个一维数组), 放入
                    for (int m = 0; m < bucketElementCounts[k]; m++) {
                        //取出元素放入到arr
                        arr[index] = bucket[k][m];
                        index++;
                    }
                }
                //第i+1轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!
                bucketElementCounts[k] = 0;
            }
            System.out.println("第" + (i + 1) + "轮,对数据位数的排序处理 arr =" + Arrays.toString(arr));
        }

    }
}

2、运行main函数,运行结果如下:

java数据结构和算法——基数排序算法_第4张图片

七、测试基数排序算法所消耗的时间示例

1、代码

package com.rf.springboot01.dataStructure.sort;

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

/**
 * @description: 测试基数排序算法所消耗的时间示例
 * @author: xiaozhi
 * @create: 2020-08-12 22:57
 */
public class RadixSort3 {
    public static void main(String[] args) {
        int arr[] = new int[10000000];
        for(int i=0;i<10000000;i++){//创建一个带有一千万个随机数的数组
            arr[i]= (int) (Math.random()*8000000); //随机生成(0到8000000之间)的数
        }
        Date data1 = new Date();
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String date1Str = simpleDateFormat.format(data1);
        System.out.println("排序前的时间是=" + date1Str);

        radixSort(arr);

        Date data2 = new Date();
        String date2Str = simpleDateFormat.format(data2);
        System.out.println("排序后的时间是=" + date2Str);
    }

    /**
     * @Description:  基数排序算法的推导过程示例方法
     * @Param: [arr]
     * @Author: xz
     * @return: void
     * @Date: 2020/8/12 22:25
     */
    public static void radixSort(int[] arr) {

        //定义一个二维数组,表示10个桶, 每个桶就是一个一维数组
        //说明
        //1. 二维数组包含10个一维数组
        //2. 为了防止在放入数的时候,数据溢出,则每个一维数组(桶),大小定为arr.length
        //3. 很明确的表示,基数排序是使用空间换时间的经典算法
        int[][] bucket = new int[10][arr.length];

        //为了记录每个桶中,实际存放了多少个数据,我们定义一个一维数组来记录各个桶的每次放入的数据个数
        //可以这么理解 比如:bucketElementCounts[0] , 记录的就是  bucket[0] 桶的放入数据个数
        int[] bucketElementCounts = new int[10];

        //1. 得到数组中最大的数的位数
        int max = arr[0]; //假设第一数就是最大数
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        //得到最大数是几位数
        int maxLength = (max + "").length();
        /**
         * @Description: 针对每个元素的个位数进行排序处理
         * @Param: [arr]
         * @Author: xz
         * @return: void
         * @Date: 2020/8/12 22:29
         */
        for (int i = 0, n = 1; i < maxLength; i++, n *= 10) {
            //(针对每个元素的对数应位进行排序处理), 第一次是个位,第二次是十位,第三次是百位..
            for (int j = 0; j < arr.length; j++) {
                //取出每个元素的个位的值
                int digitElement = arr[j] / n % 10;
                //放入到对应的桶中
                //1、bucket[digitElement] 表示个位数对应的第个位数的桶
                //2、bucketElementCounts[digitElement] 表示个位数对应的第个位数的桶的数据个数
                bucket[digitElement][bucketElementCounts[digitElement]] = arr[j];
                bucketElementCounts[digitElement]++;
            }

            //按照这个桶的顺序(一维数组的下标依次取出数据,放入原来数组)
            //遍历每一桶,并将桶中是数据,放入到原数组
            int index = 0;
            for (int k = 0; k < bucket.length; k++) {
                //如果桶中有数据,我们才放入到原数组
                if (bucketElementCounts[k] != 0) {
                    //循环该桶即第k个桶(即第k个一维数组), 放入
                    for (int m = 0; m < bucketElementCounts[k]; m++) {
                        //取出元素放入到arr
                        arr[index] = bucket[k][m];
                        index++;
                    }
                }
                //第i+1轮处理后,需要将每个 bucketElementCounts[k] = 0 !!!!
                bucketElementCounts[k] = 0;
            }
        }
    }

}

2、运行main函数,运行结果如下:
java数据结构和算法——基数排序算法_第5张图片

本地计算机,win10系统,8G内存测试带有一千万个随机数的数组,用基数排序耗时大约1秒

八、基数排序存算法注意事项

  • 因为基数排序是使用空间换时间的经典算法
  • 下图中数据量如果是8千万条,进行排序时本地计算机会报内存溢出错误

java数据结构和算法——基数排序算法_第6张图片

你可能感兴趣的:(java数据结构和算法)