排序5 - 基数排序

基数排序,之所以介绍它,是因为它有一个特点,排序的时间复杂度为O(n)。另外,基数排序是一种特殊的桶排序。

同样先问一些问题:

  1. 为什么它可以这么快,怎么和之前的不同?
  2. 为什么工程中多使用快排而不是基数排序,它有什么弊端?

桶排序

桶排序可以说是最简单最快的排序算法了,思想就是将输入数据放置到不同的桶中,然后在各个桶内再进行递归地排序。桶的数量是不唯一的,最简单的就是设置和值域相同个数的桶,比方说输入的数值范围是0-100,那么就设置101个桶,无论多少个数,都能放到这个桶内,相当简单。

缺点就是,这样设置的话,桶的个数就变成了与值域大小相关,如果只有两个数1和100000,那就要设置10000个桶,太过占空间。而且如果输入数据分布不均匀,都丢进了相同的桶,那就要继续递归的排序,这样轮数可能增加,效率也会降低。

桶排序是时间复杂度是O(n)级别,其不属于比较排序,所以不受比较排序的时间复杂度下界的限制。

具体实现没写过,也不能盗别人的代码,有兴趣的筒子们去网上找一下吧。

基数排序

基数排序是一种特殊的桶排序,其桶的个数依赖于数的进制,如十进制就以10为桶的个数。其排序思想和人脑排序很像,一位一位的比较。人脑先看最高位,若相同则看下一位;基数排序从最低位往上一位一位地排序,保证在最高位相同的情况下,较低位置已经有序。

盗用书上的一张图:

那把数字分成一位一位本身不就很耗时吗?是的没错,但这个并不会提高排序时间复杂度的量级,只是会增加常数因子。

如上例所示,基数排序分为分配和收集两个过程,在分配过程中,每次处理一位,就是把该数丢到对应的桶中。对该位处理完毕之后,进入收集环节,按照桶的顺序,也即0-9的顺序将树收集起来。很明显,这样可以保证排序的稳定性。

基数排序的实现和复杂度

怎么实现桶? 可以是数组,也可以是链式实现。

具体代码? 有兴趣的同志可以网上搜一下,应该不是很难。最近心力憔悴,也没写,希望有机会补上吧。

时间复杂度?

每一位处理都会遍历整个数集,假设最高位为第m位,那么时间复杂度为O(m+n)。

空间复杂度?

无论是数组还是链式,都会申请额外空间,这已经做不到原址排序了,所以它能这么快,也是空间换时间的结果。空间复杂度至少为O(m+n)。

回答开始的问题

  • 为什么可以这么快?

这个已经在上一节分析了。

  • 为什么它这么快,我们还用快排?

其实也是和空间复杂度有关,我猜还是占用内存太多,太麻烦。网上也查了一点资料,有人说,有些输入是没有基的,比如字符串。这个我不赞同,字符串按位比较有问题? 还在书上看到,只适用正整数排序。同样不赞同,正数负数可以分开排序再合并,小数同样可以按位比较,只是稍微麻烦了点。有人说,有些问题必须要比较才能解决。这个我有疑惑,得到排序结果不就是一种比较结果吗?其实我也没有遇到这样的问题,所以也不敢说不赞同,希望以后真的遇到了,再来这里补充一下吧。

这里我找到了《算法导论》里的一种解释,贴出来,大家参考一下。

 

写在排序篇之后

从第一篇随笔开始,恐怕也写了有半个月了,自知理解和实战能力都不算强,更谈不上拿我的博客来学习。最主要还是想自己作下记录吧,如果真的有感兴趣的小伙伴能坚持看到这里,衷心地感谢你!如果有写的不对的地方,尽管指出来啊。

知之为知之,不知为不知,存一份实事求是的敬畏之心!

posted @ 2017-12-27 17:49  年华似水丶我如风  阅读(194)  评论(0编辑  收藏  举报