桶排序

一---导读

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

以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         }
}
原文地址:https://www.cnblogs.com/YXBLOGXYY/p/14556883.html