基数排序(思路分析)
基数排序(桶排序)的介绍:
-
基数排序(radix sort)属于是"分配式排序"(distribution),又称为"桶子法"(bucket sort)或者 bin sort,顾名思义即使通过健值的各个位的值,将要排序的元素分配在某个桶中,达到排序的效果
-
基数排序是属于稳定的排序
-
基数排序(radix sort)是桶排序的扩展
-
基数排序是1887年赫尔曼-何乐礼发明的,它是这样实现的,将整数按位数切割成不同的数值,然后按每个位的数值进行比较,判断到底是要放到哪个桶中
基数排序算法(思路图解):
后序补充…
基数排序思路分析:
首先我们要得到数组中最大的数的位数,因为我们的基数排序排序的轮数就是通过我们的待排序数组中的最大元素的位数来确定的,那么我们就是要遍历数组从而拿到我们的待排序数组中的最大的数值,然后再计算出我们的最大元素的位数,这个时候计算这个最大的数的位数的时候我们可以使用一个小的算法来很快速的解决: —> 我们可以让这个最大的数加上一个空的字符串(“”) ,然后这个数就变成了一个字符串,这个时候我们直接通过这个字符串的length()方法就可以计算出我们的这个数到底有多少位,这个时候就不用我们去循环遍历了 ,就会比较省时间, 然后我们就能真正的开始我们的基数排序了,我们要先创建十个桶 (其实就是创建十个一维数组) ,但是这个时候由于创建的一维数组比较多,这个时候我们就可以改成创建一个长度为10的二维数组(这个二维数组中的每一个元素都是一个一维数组), 我们的桶就是用来装我们的待排序数组中的元素的,这个时候我们就假设最极端的情况之下,如果所有的数都是要装入一个桶中的时候为了避免我们的任意一个同发生越界的情况,这个时候我们将我们的十个桶的长度都创建为何待排序数组的长度一样的长,那么为什么是创建10个桶?
- 其实这个时候我们的10个桶就是表示的0 - 9之间的数值,我们每次都是取出一个一位数,第一次取的是待排序数组中的元素的个位数,然后是十位数,然后是百位数…,我们每一次取出一个位数之后就去和我们的桶的序号进行一个对比,我们的对应序号的桶就是装我们对应的值的数据的,如果相等就将我们的对应的待排序数值放入到我们的对应的桶中,等到所有的待排序元素放完之后,我们再将桶中的元素根据桶的顺序放回到我们的原数组中(也就是我们的待排序数组中) ,那么这样我们的一轮基数排序就执行完了,这个时候我们就分析完了一轮过程中的一个大致的思路,我们只要是重复执行就可以了,但是执行的过程中可能会有一些小的问题:
- 我们如何将桶中的元素放回到我们的待排序数组中? 我们如何知道我们的一个桶中有多少的元素?(我们必须要知道了一个桶中有多少个元素之后我们才能将我们的桶中的元素移动到我们的原数组中来)
- 那么我们要如何解决?
- 我们只能是将每个桶中有多少个元素都记录下来,由于我们是要记录十个桶中各自的每个桶中的元素的个数,所以我们要么就要使用十个变量来记录,要么我们就创建一个长度为10的一维数组来完成,很显然我们要通过创建一个长度为10的一维数组来解决,通过这个一维数组的对应位置记录我们对应编号的桶中的元素的数目的多少
- 还有一个问题: 我们一定要注意: 每一轮操作完成之后,我们都要将记录的每个桶中的元素个数归零,因为我们每一轮结束之后,也就是每一次将桶中的元素都放入到我们的原数组中之后我们就要重新开始下一轮,那么开始下一轮肯定就是要向桶中重新放入元素,这个时候如果我们没有清零,那么如果原来的这个位置的桶是有元素的,这个时候该位置下一轮中并没有添加数据到该桶中,但是我们在将桶中的元素放回到我们的原数组中去的时候就会判断出这个位置记录的是有元素的,就会将重复的元素放入放入到我们的待排序元素中,这个时候就会出错
- 所以我们一定要注意: 我们要在桶中元素放回到我们的待排序数组中的时候我们就要将记录我们桶中的数据个数的一维数组清空,就可以规避上面的问题的发生
- 但是注意: 我们这里说的清空并不是一个真正的意义上的清空,这里清空其实只是将我们的记录桶中的元素个数的一维数组清空了,这个时候我们的桶中还是有元素的,这个时候我们只能是判断的时候根据我们的记录桶中数据个数的一维数组来判断,这样就可以间接的认为我们是将桶清空了
- 我们在实际的算法中不会是执行完一轮基数排序之后才将我们的桶清空,而是会在每次将我们的任意一个桶中的元素全部放回到我们的原数组中的时候就会将我们的对应的记录该桶的一维数组对应位置的元素清空(也就是置零)
- 但是注意: 我们这里说的清空并不是一个真正的意义上的清空,这里清空其实只是将我们的记录桶中的元素个数的一维数组清空了,这个时候我们的桶中还是有元素的,这个时候我们只能是判断的时候根据我们的记录桶中数据个数的一维数组来判断,这样就可以间接的认为我们是将桶清空了
- 所以我们一定要注意: 我们要在桶中元素放回到我们的待排序数组中的时候我们就要将记录我们桶中的数据个数的一维数组清空,就可以规避上面的问题的发生
- 我们如何将桶中的元素放回到我们的待排序数组中? 我们如何知道我们的一个桶中有多少的元素?(我们必须要知道了一个桶中有多少个元素之后我们才能将我们的桶中的元素移动到我们的原数组中来)
补充:
我们的基数排序其实很简单(分入如下的几步:)
- 求最大数的位数
- 将数据放入桶中
- 将数据从桶中移入到我们的原数组中
- 2和3两步我们是要循环执行待排序数组中的最大数的位数次
补充2:
我们的基数排序是一个很经典的空间换时间的算法
- '我们在基数排序中要额外创建10个长度为待排序数组.length长度的数组
- 如果待排序数组的长度是八百万,这个时候我们就要额外创建10个长度为八百万的数组,再加上我们的待排序数组之后我们就一共要一次向内存中加载11个长度为八百万的一维数组
算法核心:
其实基数排序就是传统方式的桶排序的一种扩展, 我们首先第一次就是根据数组中所有元素的个位数进行一个排序, 取出个位数将我们的对应值都是个位数放到我们的对应桶中, 然后根据桶的顺序将我们的桶中的元素依次放回到我们的原数组中, 这样我们就是给个位数排好序了, 第二次就是根据个位数排好的数组中的元素的十位数进行一个排序, 做法还是和我们对个位数排序是一样的, 第三次就是根据十位数排好的数组中的元素的百位数进行一个排序, 最终一致排序到我们的当前的最大值对应的最高位排序完成, 那么整个排序就是完成了, 然后最终最后一次将我们的桶中的元素放入到我们的数组中的时候我们的数组中的所有元素就是一个顺序排序的情况了
- 注意: 我们如果是两个值的个位数相同的情况下, 这个时候我们第一次谁放到这个对应桶中的上面或者是下面都是可以的, 但是如果是两个值的十位数相同的情况之下, 这个时候我因为个位数是排好序的, 所以一定是个位数比较小的放到前面(这里我们是以升序为例讲解, 当然如果是个位数相同, 那么十位数也想相同的时候这个时候谁先或者是谁在后面都是一样的 —> 这个其实我们自己通过一般思维是可以想到的, 无非就是从低位到高位依次比较, 然后最终比较出结果)