基数排序与计数排序
来源:互联网 发布:java得到项目路径 编辑:程序博客网 时间:2024/05/16 01:53
基数排序
【基本思想】
首先设立r个队列,对列编号分别为0~r-1,r为待排序列中元素的基数(例如10进制数,则r=10),然后按照下面的规则对元素进行分配收集1,先按最低有效位的值,把n个元素分配到上述的r个队列中,然后从小到大将个队列中的元素依次收集起来
2,再按次低有效位的值把刚收集起来的关键字分配到r个队列中,重复收集工作
3,重复地进行上述分配和收集,直到最高有效位。(也就是说,如果位数为d,则需要重复进行d次,d由所有元素中最长的一个元素的位数计量)
为什么这样就可以完成排序呢?
以从小到大排序为例
首先当按照最低有效位完成分配和收集后,此时得到的序列,是根据元素最低有效位的值从小到大排列的。
当按照次低有效位进行第二次分配和收集后,得到的序列,是先根据元素的次低有效位的值从小到大排列,然后再根据最低有效位的值从小到大排列。
以此类推,当按照最高有效位进行最后一次分配和收集后,得到的序列,是先根据元素的最高有效位的值从小到大排列,再根据次高有效位排列,。。。,再根据次低有效位,再根据最低有效位。自然就完成了每个元素的从小到大排列。
【空间复杂度】O(n+r)
【时间复杂度】
平均情况:O(d(n+r))
因为每一趟分配的时间开销是O(n),收集的开销是O(r),因此执行d趟的时间开销为O(d(n+r)),通常d,r为常数
最好情况:O(d(n+r))
最坏情况:O(d(n+r))
【稳定性】稳定
【优点】
稳定排序;时间复杂度可以突破基于关键字比较排序法的下界O(n)
【缺点】
需要额外的辅助空间
- /**
- * 基数排序
- * @param arr
- */
- public static void radixSort(int[] arr) {
- //获得待排序列元素中的最大位数
- int maxBit = getMaxBit(arr);
- //对每一位分别进行分配和收集
- for (int bit = 1; bit <= maxBit; bit++) {
- //分配
- List<List<Integer>> buf = distribute(arr, bit);
- //收集
- collect(arr, buf);
- }
- }
- private static void collect(int[] arr, List<List<Integer>> buf) {
- int i = 0;
- //收集,依次将每个队列中的元素读出
- for (List<Integer> temp : buf) {
- for (int ele : temp) {
- arr[i++] = ele;
- }
- }
- }
- private static int getMaxBit(int[] arr) {
- int maxBit = 0;
- int len = 0;
- for (int ele : arr) {
- //利用字符串的length()方法获得元素位数
- len = (ele + "").length();
- if (len > maxBit) {
- maxBit = len;
- }
- }
- return maxBit;
- }
- //分配
- private static List<List<Integer>> distribute(int[] arr, int bit) {
- List<List<Integer>> buf = new ArrayList<>();
- //构建r个队列
- for (int i = 0; i < 10; i++) {
- buf.add(new ArrayList<>());
- }
- for (int ele : arr) {
- int value = getValueByBit(ele, bit);
- //根据每个元素指定位数上的值,将元素存放到对应的队列上
- buf.get(value).add(ele);
- }
- return buf;
- }
- //得到指定位数上的值
- private static int getValueByBit(int ele, int bit) {
- //没有该位,则返回0
- int value = 0;
- String temp = ele + "";
- if (temp.length() >= bit) {
- value = (int) (temp.charAt(temp.length() - bit) - '0');
- }
- return value;
- }
【本算法解读】
算法针对的是十进制数,所以r=10
算法首先获取到待排序列元素中的最大位数。然后按照基数排序的思想,对元素的每一位进行分配和收集。
分配distribute()方法:首先构建了r=10个队列,对应编号即是0~9。根据给定的位数,得到待排序列中每个元素在该位上的值,若元素没有该位,则返回0。根据每位上的值,将该元素放入相应的队列。完成一次分配。
收集collect()方法:依次从r个队列中读出其中的元素值,并将其存入原始序列中,即完成了一次收集。
【举个栗子】
对于待排序列413,10,8,28
首先获取到待排序列的最大位数,即为3。
然后根据每一位的值进行分配和收集,分配过程如下图:
由于是10进制数,所以构造10个队列,0~9。
首先从最低有效位开始,每个元素在该位上对应的值分别是3,0,8,8,根据该值,将对应元素放入对应的队列。分配结束后,依次从每个队列上读取元素值存入原始序列。可以看到一次分配以后,元素已经按照最低有效位从小到大排列。继续位数逐渐增大,直到最高有效位,重复上述操作即可完成排序。
计数排序
【基本思想】
计数排序是基于非比较排序,主要用于对于一定范围内的整数进行排序。采用的是空间换时间的方法。针对待排序列中的每一个元素x,得到序列中小于x的元素个数,有了这一信息可以直接把x放到最终的输出序列的正确位置上。 计数排序之所以能做到线性时间复杂度是因为使用了索引的思想。
对于下面我即将给出的算法,它的限制条件是待排序列中的元素是有限个正整数(包括0,由于将元素值作为数组下标),最大值用k=O(n)表示,元素个数用n表示。它利用元素的实际值来确定它们在输出序列中的位置
【空间复杂度】O(n+k)
【时间复杂度】
平均情况:O(n+k)
最好情况:O(n+k)
最坏情况:O(n+k)
【稳定性】稳定
【优点】
稳定,在k值较小时突破了基于比较的排序算法下界
【缺点】
存在前提条件,需要大量额外空间,k值较大时效率很低
- /**
- * 计数排序
- * @param arr
- */
- public static void countSort(int[] arr) {
- int max = getMax(arr);
- int count[] = new int[max + 1]; //此时数组中元素值均被初始化为0
- //在以元素值为
- for (int ele : arr) {
- count[ele]++;
- }
- int k = 0;
- for (int i = 0; i <= max; i++) {
- for (int j = 0; j < count[i]; j++) {
- arr[k++] = i;
- }
- }
- }
- //获得待排元素中的最大值
- private static int getMax(int[] arr) {
- int max = 0;
- for (int ele : arr) {
- if (ele > max) {
- max = ele;
- }
- }
- return max;
- }
【本算法解读】
可以看到算法首先获得待排序列元素中的最大值,然后构建最大值+1的长度的计数数组。遍历待排序列的每个元素,并在以元素值为下标的数组值中加1。然后遍历计数数组,若对应下标的位置上值大于0(等于几就表示有几个元素),则表示存在有元素且其值为下标的大小。将该元素添加到原始序列中。由于下标是从小到大的,所以对应得到的序列也是从小到大排列的。【举个栗子】
对于待排序列4,0,2,8,2
首先获取最大值即为0,然后构建8+1长度的计数数组。初始化时,计数数组中的值均为0.如下图所示:
最后过遍历计数数组,如,遍历到0下标位置,数组值为1,表示有一个元素,元素值是下标0,添加到原始序列中。遍历到2下标位置,数组值为2,表示有两个元素,元素值均为下标2,将两个元素依次添加到原始序列中。以此类推,最终得到有序序列0,2,2,4,8。
- 基数排序与计数排序
- 桶排序与基数排序与计数基数排序
- 计数排序、基数排序与桶排序
- 桶排序与基数排序、计数排序
- 常用排序算法之计数排序,基数排序与桶排序
- 计数排序,基数排序
- 计数排序和基数排序
- 计数排序-基数排序
- 计数排序和基数排序
- 基数排序和计数排序
- 计数排序和基数排序
- 计数排序+基数排序
- 计数排序和基数排序
- 基数排序/计数排序
- 计数排序和基数排序
- 基数排序,计数排序
- 计数排序和基数排序
- 计数排序实现基数排序
- java基础--17 自定义的RandomUtils类--用于产生各种随机串的工具类
- Servlet案例五
- java内存布局与GC
- nyist 128 前缀式计算
- 冒泡排序算法的改进
- 基数排序与计数排序
- Servlet案例六
- hdu 5927 Auxiliary Set
- 数据结构学习笔记--栈
- 微信小程序入门基础(2)—视图层
- 详解堆栈的几种实现方法——C语言版
- currenthashmap
- {模板}spfa
- 每天一点小姿势——C语言语法记不住咋办(2)