「这是我参与2022首次更文挑战的第16天,活动详情查看:2022首次更文挑战」
在说基数排序之前,先简单记录一下计数排序。计数排序的确不同于桶排。
计数排序
计数排序适合整数数值排序,且值域范围有限。 比如给高考考生的得分进行排序,值域范围是[0, 750]十分有限。
流程是先统计每个数值对应的元素的次数,把相同数值的元素划分到一个区间, 然后计算每个区间的开始下标,通过求前缀和的方式计算下标,按这个顺序 , 给它放回去,就排序完成了。三轮迭代,时间复杂度O(n).
基数排序
基数排序是具有相对稳定性的排序。
假设,我们现在排序的目标是一个只包含两位数的数组。 我们用基数排序的大概步骤是这样的。
1 对每个元素的个位进行计数排序
2 对每个元素的十位进行计数排序
假设,数组本来是这样的[ 81, 39, 4, 85, 17, 14, 83, 80 ]
我们进行第一轮个位排序, [80, 81, 83, 4,14, 85, 17, 39 ]
从这个结果上就能看出 稳定性是什么。 4之所以排在14前面,不是因为4比14小, 而是因为在原数组中4 就在14的前面。 个位排序之后,不同个位的数肯定不在一块,而个位相同的数的相对顺序还是保持排序之前的顺序。
我们再进行第二轮十位数排序, [4, 14, 17 ,39 , 80 , 81, 83, 85 ].
排序就完成了。 对于二位数,他们的十位和个位都是升序,那么他们本身肯定就是升序。
高位和低位
上面的做法只适用十进制的两位数, 如果三位数,难懂要三排,五位数五排?。
当然不是, 我们统一把小于2的32次的数,当做是2^16(65536)进制, 这样这些数就都只有两位, 高16位和低16位。 所以现在的问题就是如何取得高十六位和低十六位,简单的做法就是取模。
但是有更好的做法就是位与运算,因为我们限定了范围和进制正好就是2的16次, 位与运算的结果就是只有两者都是1才是1,这样取低16位就只需要和 65536-1 进行位与运算 , 取高16位则需要 和 0xffff0000 进行位与运算 ,然后右移 16 。 注意 位与运算的优先级高于位移运算。
附上leetcode 164. 最大间距