【经典排序算法】8. 计数排序

之前的排序都是基于比较的排序。计数排序,包括后面桶排序和基数排序则不是。

计数排序,顾名思义,记录元素的出现次数来排序。指定一个新数组,数组索引用来记录存储的元素,数组数字记录出现元素的次数。

计数排序经过一定的改进可以是out-place,稳定的线性时间排序算法。该排序适用于序列分布比较集中的情况,并且边界已知且比较小,并且排序的元素必须是整数。如果序列分布过于稀疏,边界太大,则开辟新数组的空间占用会很大。

public class Main {

    public static void main(String[] args) {
        int[] arr = {3, 3, 5, 6, 2, 1};
        System.out.print("排序前:");
        arrPrint(arr);
        int[] out = CountSort(arr);
        System.out.print("排序后:");
        arrPrint(out);
    }

    // 计数排序
    //
    // 初始化max和min为arr的第一个元素,第一个for循环反复取arr中的最大值赋给max,
    // 反复取arr中的最小值赋给min,这样就得到arr中的最大最小值max,min。
    // max-min+1的长度就是计数数组count的长度。
    // 第二个for循环,将arr中元素的出现次数在count中计数,count的索引为 元素-min,
    // count的元素表示对应arr元素的出现次数,(本实例得到的count为[1, 1, 2, 0, 1, 1])。
    // 简单版本的计数排序索引直接用来存储arr元素,因为索引必须从0开始,
    // 假如arr中的min是100,max是110,arr元素分布在100-110,
    // 那开辟的count数组中0-99的位置都被浪费了。所以我们的count数组长度设为
    // arr最大max到最小值min的长度max-min+1,arr元素对应的索引值即为 元素-min。
    // 第三个for循环,遍历计数数组count中的元素,将前面的计数结果累加到后一位的计数结果中
    // (本实例得到的count为[1, 2, 4, 4, 5, 6])。count的索引与arr元素对应关系不变,
    // 此时count的元素表示小于等于对应arr元素的元素数量。比如实例arr中的2这个数字,
    // 对应到count的索引为 2-min = 2-1 = 1,索引元素count[1]=2,所以小于等于arr中2这个数
    // 的数字总共有 count[1]=2 个。
    //
    // 创建输出结果数组result,
    // 第四个for循环,倒叙遍历待排序数组arr,遍历索引为j,遍历元素为arr[j],
    // 那么对应到count的索引为arr[j]-min,索引对应元素为count[arr[j]-min],
    // 那么根据count数组的含义,在arr中,小于等于arr[j]的元素总共有count[arr[j]-min]个,
    // 不算上arr[j]等于arr[j]自己这种情况,那么小于等于arr[j]的元素除自己以外,
    // 总共有count[arr[j]-min] - 1个。既然有 count[arr[j]-min] - 1 个数字小于等于arr[j],
    // 那么数组排序的时候,arr[j]在数组里就应该排名第 count[arr[j]-min] - 1 位这个位置。
    // 我们直接在result的count[arr[j]-min] - 1这个位置将arr[j]填入。
    // 即result[count[arr[j] - min] - 1] = arr[j]。填入result之后,
    // arr[j]在计数数组count的对应计数 count[arr[j]-min] 减1,j继续向左遍历,
    // 如此循环反复,最后可将arr中的数按照它们对应的大小排序好。循环结束,返回result即可。
    private static int[] CountSort(int[] arr) {
        int max = arr[0];
        int min = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (max < arr[i])
                max = arr[i];
            if (min > arr[i])
                min = arr[i];
        }

        int[] count = new int[max - min + 1];
        for (int num: arr) {
            count[num - min]++;
        }
        for (int i = 1; i < count.length; i++) {
            count[i] += count[i - 1];
        }

        int[] result = new int[arr.length];
        for (int j = arr.length - 1; j >= 0; j--) {
            result[count[arr[j] - min] - 1] = arr[j];
            count[arr[j] - min]--;
        }
        return result;
    }

    // 辅助函数:将int[] 打印出来
    private static void arrPrint(int[] arr) {
        StringBuilder str = new StringBuilder();
        str.append("[");
        for (int v : arr) {
            str.append(v + ", ");
        }
        str.delete(str.length() - 2, str.length());
        str.append("]");
        System.out.println(str.toString());
    }
}


实例的动画演示如下:

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/fisherish/article/details/114280356