zoukankan      html  css  js  c++  java
  • 桶排序

    一---导读

      我们先思考这样一个数学问题,如何取出一个数的个位,十位,百位。。。?

    以128为例,要取出个位8我们可以对其进行直接取余10操作 128 % 10 = 8,取出十位2我们可以先对其除以10再取余10。

    128 % 10 = 12,12 % 10 = 2;

    二---桶排算法思路图解

    假设现在有数组arr{3, 15, 122, 64}

    我们对其用桶排进行排序步骤如下:

    第一轮:对个位进行排序

    第二轮:对十位进行排序

    第三轮:对百位进行排序

    通过以上的图片我们可以看出,只要排三次,也就是到最高位百位,即可得出想要的结果。

     注:基数排序其实就是桶排序的精简版本

    代码实现:

    package Sort;
    
    import java.util.Arrays;
    
    public class RadixSort {
        public static void main(String[] args) {
            int[] arr = {3, 15, 122, 64};
            System.out.println("排序前" + Arrays.toString(arr));
    
            radixSort(arr);
    
        }
    
        // 基数排序
       public static void radixSort(int[] arr) {
    
    
            // 定义一个二维数组,表示10个桶,每个桶就是一个一维数组
            // 说明
            // 1 二维数组包含10个一维数组
            // 2 为了防止数据溢出,则每个一维数组(桶)的大小为arr.length
            // 3 很明显基数排序是使用空间换时间的经典算法
            int[][] bucket = new int[10][arr.length];
            //为了记录每个桶中实际存放了多少个数据,我们定义一个一维数组来记录各个桶每次放入的数据的个数
            // 可以这样理解
            // bucketElementCount[0],记录的就是bucket[0]桶的放入数据个数,可以看做10个指针(没学过c/c++忽略)
            // 可以这样理解,bucketElementCounts[0],记录的是bucket[0]桶的放入数据个数。
            int[] bucketElementCounts = new int[10];
    
            // 第一轮(针对个位进行排序处理)
            for (int j = 0; j < arr.length ; j++) {
                // 取出每个元素的个位
                int digitOfElment = arr[j] / 1 % 10;
                // 放入到对应的桶中,就是刚刚算出来的这个桶
                bucket[digitOfElment][bucketElementCounts[digitOfElment]] = arr[j];
                bucketElementCounts[digitOfElment]++;
            }
            // 按照这个桶的顺序 (一维数组的下标依次取出数据,放入原来数组)
    
            int index = 0;
            // 遍历每一个桶,并将桶中的数据放到原数组
            for (int k = 0; k < bucketElementCounts.length ;  k++) {
                // 如果桶中有数据,我们才放入到原数组。
                if(bucketElementCounts[k] != 0) {
                    // 循环该桶即第k个桶,即第k个一维数组,放入
                    for (int l = 0; l < bucketElementCounts[k] ;  l++) {
                        // 取出元素放到arr
                        arr[index++] = bucket[k][l];
    
                    }
                }
                // 第一轮处理后需要将 每个bucketElementCounts[k]=0
                bucketElementCounts[k] = 0;
            }
    
            System.out.println("第一轮,对个位的数据的处理" + Arrays.toString(arr));
    
    
            // 第二轮(针对十位进行排序处理)
            for (int j = 0; j < arr.length ; j++) {
                // 取出每个元素的个位
                int digitOfElment = arr[j] / 10 % 10;
                // 放入到对应的桶中,就是刚刚算出来的这个桶
                bucket[digitOfElment][bucketElementCounts[digitOfElment]] = arr[j];
                bucketElementCounts[digitOfElment]++;
            }
            // 按照这个桶的顺序 (一维数组的下标依次取出数据,放入原来数组)
    
             index = 0;
            // 遍历每一个桶,并将桶中的数据放到原数组
            for (int k = 0; k < bucketElementCounts.length ;  k++) {
                // 如果桶中有数据,我们才放入到原数组。
                // 注意,上一轮结束后我们并没有把桶里的数清零。第二轮再放的话需要重新进行累积,所以会报错Index 6 out of bounds for length 6
                if(bucketElementCounts[k] != 0) {
                    // 循环该桶即第k个桶,即第k个一维数组,放入
                    for (int l = 0; l < bucketElementCounts[k] ;  l++) {
                        // 取出元素放到arr
                        arr[index++] = bucket[k][l];
    
                    }
                }
                bucketElementCounts[k] = 0;
            }
    
            System.out.println("第二轮,对个位的数据的处理" + Arrays.toString(arr));
    
            // 第三轮(针对十位进行排序处理)
            for (int j = 0; j < arr.length; j++) {
                // 取出每个元素的个位
                int digitOfElment = arr[j] / 100 % 10;
                // 放入到对应的桶中,就是刚刚算出来的这个桶
                bucket[digitOfElment][bucketElementCounts[digitOfElment]] = arr[j];
                bucketElementCounts[digitOfElment]++;
            }
            // 按照这个桶的顺序 (一维数组的下标依次取出数据,放入原来数组)
    
            index = 0;
            // 遍历每一个桶,并将桶中的数据放到原数组
            for (int k = 0; k < bucketElementCounts.length; k++) {
                // 如果桶中有数据,我们才放入到原数组。
                // 注意,上一轮结束后我们并没有把桶里的数清零。第二轮再放的话需要重新进行累积,所以会报错Index 6 out of bounds for length 6
                if (bucketElementCounts[k] != 0) {
                    // 循环该桶即第k个桶,即第k个一维数组,放入
                    for (int l = 0; l < bucketElementCounts[k]; l++) {
                        // 取出元素放到arr
                        arr[index++] = bucket[k][l];
    
                    }
                }
            }
    
            System.out.println("第三轮,对个位的数据的处理" + Arrays.toString(arr));
    
    
        }
    
        
    }
    

      

    优化代码:我们发现上面一-三步可以用for循环来包含。

     1 package Sort;
     2 
     3 import java.util.Arrays;
     4 
     5 public class RadixSortTest {
     6     public static void main(String[] args) {
     7         int[] arr = {13, 2, 164, 259};
     8         System.out.println("原数组为:" + Arrays.toString(arr));
     9         RadixSort1(arr);
    10     }
    11 
    12     public static void RadixSort1(int[] arr) {
    13         // 构造出桶
    14         int[][] bucket =  new int[10][arr.length];
    15         // 用一个数组来存放每个桶中有多少元素 ,有10个桶就是10个。
    16         int[] bucketElementCounts = new int[10];
    17 
    18         // 第一轮排序
    19         // 取出数据的个位23 
    24         // 获取最大的数的长度
    25         int max = arr[0]; // 假设第一个数就是最大的
    26         for(int m = 1; m < arr.length; m++) {
    27             if(max < arr[m]) {
    28                 max =  arr[m];
    29             }
    30         }
    31         System.out.println("最大的数为:" + max);
    32         // 获取最大数的长度
    33         int maxlength = (max + "").length(); // 加空串使其变为字符串,注意空串之间不要打空格,否则长度会加1,可以调用length函数
    34 
    35 
    36 
    37         for(int l = 0, n = 1; l < maxlength; l++, n *= 10) {
    38             for (int i = 0; i < arr.length; i++) {  // 注意这里不是arr.length - 1,要不然最后一位处理不到
    39                 int digit = arr[i] / n % 10;
    40                 // 放入对应的桶中
    41                 bucket[digit][bucketElementCounts[digit]] = arr[i];
    42                 // 记录桶数据的数组对应位置加1
    43                 bucketElementCounts[digit]++;
    44             }
    45             // 按照当前顺序取出桶中的元素放回数组中
    46             int index = 0;
    47             for (int j = 0; j < bucket.length; j++) {
    48                 // 先判断这个桶中是否有元素,有元素的话再循环取出
    49                 if (bucketElementCounts[j] != 0) {
    50                     for (int k = 0; k < bucketElementCounts[j]; k++) {
    51                         arr[index++] = bucket[j][k];
    52                     }
    53                 }
    54                 bucketElementCounts[j] = 0;
    55 
    56             }
    57             count++;
    58             System.out.println("第" + count + "轮排序完" + Arrays.toString(arr));
    59         }
    }
  • 相关阅读:
    MySQL权限整理及授权命令
    netstat
    5.7.20 多实例——MGR部署实战
    ELK(V7)部署与架构分析
    服务器安全之iptables
    记一次MySQL中Waiting for table metadata lock的解决方法
    MySQL在线DDL gh-ost 使用说明
    如何只查看配置文件中未被注释的有效配置行
    nginx的http负载均衡
    nginx实现正向代理和反向代理
  • 原文地址:https://www.cnblogs.com/YXBLOGXYY/p/14556883.html
Copyright © 2011-2022 走看看