关于基数排序的一些思考

       之前一直觉得排序算法时间复杂度的极限就是O(nlogn),今天看了基数排序,时间复杂度居然是O(n),觉得非常有意思,写一篇博客记录一些新的知识。

       之前接触的排序在具体实现的时候,算法核心都会回归到元素的一个比较规则,在JAVA语法中则具体为对比较接口的实现,这样的排序都被称为基于比较的排序,他们所掌握的信息只是元素的一个比较规则,我们熟悉的归并、快排等都是其中的优秀算法。而基于比较的排序都已经被证明时间复杂度不会低于O(nlogn)。

       基数排序为了进一步降低时间复杂度,必然就要跳脱基于比较的排序的局限性,即必须利用元素更多的信息,而基数排序是这么做的:将一个元素所包含的信息分为不同的部分,然后索要元素不同部分之间的比较规则(比如不同部分的权重或者不同部分之间的优先关系),以及各个元素在同一部分的比较规则。

       有了这些信息之后,基数排序就会先后执行不同部分的规则对元素集合排序,通常先执行权重最低部分的比较规则,返回的结果接着执行权重下一低的规则,以此类推。这样做的好处是先执行的低权重规则会被后执行的高权重规则自然地覆盖,而且显然不用担心这个过程会造成任何信息丢失,因此当所有信息都被利用上时,即按照不同规则加权完成迭代的时候,最终排序就完成了。

       基数排序索要的信息更多,那么限制就也更高,不过幸好,绝大多数时候并不需要考虑多么复杂的情况,比如在对十进制整数进行基数排序的时候:

       1、将整数依照位权分为不同部分,比如四位整数就能分为四个部分:个、十、百、千
       2、得到不同部分相互的比较规则:个<十<百<千
       3、得到各个部分的比较规则,在当前情况下,有一个通用比较规则:0<1<2<3<4<5<6<7<8<9
       4、排序:
              例如输入:
                     1244、2234、1334、1235、1234
              依照个位部分第一次迭代:
                     1244、2234、1334、1234||1235
              依照十位部分第二次迭代:
                     2234、1334、1234、1235||1244
              依照百位部分第三次迭代:
                     2234、1234、1235、1244||1334
              依照千位部分第四次迭代:
                     1234、1235、1244、1334||2234
              处理完毕。

       你注意到我有时用顿号有时用||代表分隔,这是为了以示区别,因为实际操作中在按照元素第i部分的比较规则进行第i次迭代时,开始时会依照第i次迭代部分的比较规则分配元素,也就是先将元素集合分为ri个小集合,ri为该元素集合在第i个部分拥有的不同的值的总数量,类比到十进制整数的情况,那么ri大小就都是10,也就是十进制的基数,接着相同特征值的元素就归类到同一个小集合,比如之前的例子中,第一次迭代有两个小集合不为空,分别是个位为3和个位为4。像这样分配完所有元素之后便可以合并,合并顺序也依照第i部分的比较规则,重新合并为一个整体之后,就算完成了第i次迭代,然后将这个整体传入第i+1次迭代。这就是基数排序属于分配式排序的原因,它还因此被称为“桶子法”。

       分配式排序的分类和“桶子法”的别名确实很符合基数排序的具体实现,但是我却并没有这么介绍基数排序,甚至是故意弱化了“将元素分配到许多桶子”这一过程的存在感,而反复的强调基数排序索要的信息是两种“比较规则”。这其实就是我想表达的东西,为什么是两种?而不是两个?又是否可以是三种四种?我想应该会有读者理解我的意思,我本能的想到矩阵变换和多维矩阵,但是由于思而不学的时候太多了,说不出其他更多的东西了,唉,希望这辈子能别老这样。

       这篇博客写到这里就算完了,顺带补充一下,基数排序的时间复杂度可以被认为是O(n),但其实他的常数项并非完全是常数项,这个很好分析,每次迭代需要分配n个元素,每个元素都要从ri个桶子中找一个归类进去,(ri是第i部分的不同值总数),迭代次数是m(共计m个部分)。可以推测,基数排序的实际效率在输入规模不太大的时候和快排等应该相差不大,而在大输入规模的情况下,若输入数据不重复,基数排序的常数项通常和输入规模存在对数关系,再加上基数排序的其他不便之处比如可能多线程化较复杂等,我想这些也许便是基数排序虽然时间复杂度更低但却更低调的原因吧。

       看到这的读者如果有什么想法建议或者是指正错误都没关系,请尽管在评论区留言。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值