线性排序 -- 计数排序

1、定义

计数排序是桶排序的一种特殊情况,当要排序的n个数据,所处的范围并不大的时候,比如最大值是K,我们就可以把数据划分为k个桶,每个桶内的数值都是相同的,省去了桶内排序的时间。

2、举例说明

高考查分系统:比如50万考生,满分900,最低0分,最高900分,那么可以对应901个桶,对应分数从0~900,根据考生的成绩划分到这901个桶里,桶内都是分数相同的考生,不需要排序。因此只需要依次扫描每个桶,将桶内的考生依次输出到一个数组中,就实现了50万个考生的成绩排序,所以时间复杂度是O(n)。

3、实例计数排序

假设只有八个考生,分数在0~5之间,考生分数为:A[8] = {2, 5, 3, 0, 2, 3, 0, 3},对这8个考生成绩排序。

分析:

考生的成绩从0~5,我们使用大小为6的数组C[6]表示桶,其中下标对应分数。不过C[6]存储的并不是考生,而是对应分数的考生个数,那么遍历一遍C[6],就可以得到考生个数。

                                   

从图中可以看出,分数为3的考生有3个,小于等于3的有4个,所以成绩为3的考生在排序之后的有序数组R[8]中,会在下标4、5、6三个位置。

                                  

如何快速计算每个考生在有序数组中的位置,思路如下:

我们对C[6]数组顺序求和,如下所示,C[k]里面就存储了小于等于k的考生个数:

                                 

我们从后往前依次扫描数组A,比如,扫描到3时,我们可以从数组C中取出下标为3的值7,意思就是分数小于等于3的考生一共有7人,也就是说3数数组R中的第7个元素(就是下标6对应的位置),当3放入R数组中,小于等于3的人数就剩6个,更新C[3]的值,减1等于6。

以此内推,当扫描到第二个3的时候,就放入R[5]中,当扫描完数组A后,数组R的数据就是有序的:

                                

通过上面描述,代码如下:

    // 计数排序
    public static void countingSort(int[] arr, int n){
        if(n <=1) return;

        // 查找数组中的数据范围,找到最大值,当前默认最小值是0
        int maxScore = arr[0];
        for(int i=0; i<n ;i++){
            if(maxScore < arr[i]){
                maxScore = arr[i];
            }
        }

        // 申请计数数组,下标大小 0 - max
        int[] count = new int[maxScore + 1];
        for (int i=0; i<=maxScore; i++){
            count[i] = 0;
        }

        // 计算每个元素的个数,放入count中
        for(int i=0; i<n; i++){
            count[arr[i]]++;
        }

        // 依次累加
        for(int i=1; i<=maxScore; i++){
            count[i] = count[i] + count[i-1];
        }

        // 临时数组R,用于存储排序之后的结果
        int[] r = new int[n];
        // 计算排序 -- 这步就是对应到最后一幅图
        for (int i=n-1; i>=0; i--){
            int index = count[arr[i]];
            r[index] = arr[i];
            count[arr[i]]--;
        }

        // 拷贝结果到arr中
        for (int i=0; i<n; i++){
            arr[i] = r[i];
        }
    }

从代码中可以清晰的看出,主要分三步:1、申请范围数组;2、对每个元素进行计数,并且一次累加;3、遍历计数数组,将遍历结果存到临时数组R中。最后就得到有序数组。

注意:

计数排序只能用于用在数据范围不大的场景中,如果数据范围k比要排序的数据n大很多,就不适合用计数排序了,而且,计数排序只能给非负整数排序,如果要排序的数据是其他类型,那么在不改变其大小的情况下,转换为非负整数。

说明:以上整理自极客邦数据结构与算法之美课程。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值