[Classic sorting algorithm] 8. Counting sorting

The previous sorting is based on comparison sorting. Counting sorting, including the latter bucket sorting and radix sorting is not.

Counting sorting, as the name implies, records the number of occurrences of elements to sort. Specify a new array, the array index is used to record the stored elements, and the array number records the number of occurrences of the element.

Counting sorting can be an out-place, stable linear time sorting algorithm after a certain improvement. This sort is suitable for the situation where the sequence distribution is relatively concentrated, and the boundary is known and relatively small, and the elements of the sort must be integers. If the sequence distribution is too sparse and the boundary is too large, the space occupied by opening up a new array will be large.

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());
    }
}


The animated demonstration of the example is as follows:

Insert picture description here

Guess you like

Origin blog.csdn.net/fisherish/article/details/114280356