如何给广东省人口按照年龄来排序?

      据统计,广东省人口已经突破一亿人,是中国人口最多的省份,那么我们如何快速给广东省人口按照年龄来排序呢?大家都知道快速排序的时间复杂度是O(nlogn),那还有比快速排序更快的算法吗?那就跟我来一探究竟。

计数排序

      计数排序的思想很简单:当要排序 n 个数据,并且n的取值范围并不大的时候,比如最大值是k,我们就可以把数据划分成k个桶,每个桶内的数据值都是相同的。我们来观察一下年龄这个数据的特征是啥?我们假设最大的年龄是120岁,最小的年龄是0岁,那么年龄的数据范围是0-120岁,这就说明年龄的取值范围不大,正好符合计数排序的数据要求。所以我们可以分成121个桶,对应年龄0~120。我们根据人的年龄,将所有广东省的人口划入

这个121个桶里。桶内的数据都是年龄相同的人,所以不需要再排序。我们只需要依次扫描每个桶,将桶内的数据输出,就实现了广东省人口按年龄来排序,因为只是涉及到了遍历操作,所以时间复杂度是O(n)。 

     我们接下来来看一下计数排序的具体实现。我们还拿年龄的例子来看,为了方便说明,我们将数据规模进行了简化处理,假设只有7个人,年龄的范围是0~5。这7个人的年龄放在一个数组A中。他们分别是5,4,3,3,2,4,0。

     年龄的范围是0~5,我们使用大小为6的数组C表示桶,其中数组的下标对应的是年龄,C数组存储的是对应年龄的人数。我们遍历一遍人口年龄数据,就可以给数组C初始化完成。

图片

      从图中可以看出,年龄为3的人数是2,小于3的人数有2个,所以,年龄为3的人在排序之后的有序数组中,会保存下标2,3的位置。

图片

      那我们如何快速计算出,每个年龄的人在有序数组中对应的存储位置呢?这个处理方法非常巧妙,很不容易想到。思路是这样的:我们对数组C顺序求和,数组C存储的数据就变成了下面这样子。C[k]里存储小于等于年龄k的人的个数。

图片

        接下来是最核心的部分了。我们从后到前依次遍历数组A。比如,当扫描到0时,我们从数组C中取出下标为0的值1,也就是说,到目前为止,包括自己在内,年龄小于等于 0 的人数有 1 个,也就是说 0 是数组 R 中的第 1 个元素(也就是数组 R 中下标为 0 的位置)。当0放入到数组 R 中后,小于等于 0 的元素就只剩下了 1 个了,所以相应的 C[0]要减 1,变成 0。当我们扫描完整个数组 A 后,数组 R 内的数据就是按照分数从小到大有序排列的了。

图片

      接下来,我们来看一下代码是如何实现的。

def countingSort(a,n):
     if n<=1:
          return

     #求出最大值
     max_data=max(a)

     c=[0 for i in range(max_data+1)]

     #初始化C
     for j in a:
          c[j]+=1

     ##依次累加
     for i in range(1,max_data+1) :
         c[i] = c[i-1] + c[i]

     r=[0 for i in range(n)]

     for i in range(n-1,-1,-1):
          index = c[a[i]]-1
          r[index] = a[i]
          c[a[i]]-=1
     return r


a=[5,4,3,3,2,4,0]
r=countingSort(a,len(a))
print(r)

  

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

     计数排序你学会了吗?欢迎留言和我一起讨论,更多有趣内容,请关注公众号。

image.png

posted @ 2021-07-20 10:28  公众号程序员学长  阅读(716)  评论(2编辑  收藏  举报