计数排序+桶排序+基数排序 详讲(思路+图解+代码详解)

文章目录

  • 计数排序+桶排序+基数排序
    • 一、计数排序
          • 概念:
          • 写法一:
          • 写法二:
    • 二、桶排序
        • 概念
        • 代码
    • 三、基数排序
      • 概念
      • 1.LSD排序法(最低位优先法)
      • 2.MSD排序法(最高位优先法)
    • 基数排序VS基数排序VS桶排序


计数排序+桶排序+基数排序


一、计数排序

在这里插入图片描述

  • 时间复杂度:
  • 空间复杂度:
  • 稳定性:稳定
概念:
  • 非基于比较的排序

  • 计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用

    1.统计相同元素出现的个数

    2.根据统计的结果将序列回收到原来的序列中

  • 计数排序使用的场景:给出指定范围内的数据进行排序

  • 使用场景:一组集中在某个范围内的数据

写法一:
  • 通过遍历计数数组,循环输出计数数组存的次数

在这里插入图片描述

  • 1.遍历数组找到最小值最大值
  • 2.根据最大最小值,申请一个计数数组
  • 3.遍历待排数组进行计数
  • 4.遍历计数数组进行输出
 /**
     * 计数排序
     *无法保证稳定
     * @param array
     */
    public static void countSort2(int[] array) {
        //1.遍历数组找到最大值和最小值
        int MAX = array[0];
        int MIN = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > MAX) {
                MAX = array[i];
            }
            if (array[i] < MIN) {
                MIN = array[i];
            }
        }
        //2.根据最大最小值,申请一个计数数组
        int len = MAX - MIN + 1;//长度
        int[] count = new int[len];

        //3. 遍历待排数组进行计数
        for (int i = 0; i < array.length; i++) {
            count[array[i] - MIN]++;
        }

        //4.遍历计数数组进行输出
        int index = 0;//array数组新的下标
        for (int i = 0; i < count.length; i++) {
            while (count[i] > 0) {
                array[index] = i + MIN;//+最小值,求出真正的数
                count[i]--;
                index++;
            }
        }
    }
写法二:
  • 写定数组的大小,用临时数组存储结构
  • 计算每个元素在排序后的数组中的最终位置
  • 根据计数数组将元素放到临时数组b中,实现排序
  • 从后往前,根据原来数组的内容,在计数数组中找到要填写在b数组中的位置,
  • 计数数组记录的不再是数字出现是次数,而是应该在数组中存放的位置下标

在这里插入图片描述

 /**
     * 计数排序
     *稳定
     * @param array
     */
    public static void countSort(int[] array) {
        int len = array.length;
        final int MAX = 256;//常量确定数组大小
        int[] c = new int[MAX];//计数数组
        int[] b = new int[MAX];//临时数组,存放结果

        //统计每个元素的出现次,进行计数
        for (int i = 0; i < len; i++) {
            c[array[i]]++;// 将a[i]作为索引,对应计数数组c中的位置加1
        }

        // 计算每个元素在排序后的数组中的最终位置
        for (int i = 1; i < MAX; i++) {
            c[i] += c[i - 1];// 计数数组中每个元素的值等于它前面所有元素的值之和
        }

        // 根据计数数组将元素放到临时数组b中,实现排序
        for (int i = len - 1; i >= 0; i--) {
            b[c[array[i]] - 1] = array[i];// 将a[i]放入临时数组b中的正确位置
            c[array[i]]--;// 对应计数数组c中的位置减1,确保相同元素能够放在正确的位置
        }
        // 将临时数组b中的元素复制回原数组a,完成排序
        for (int i = 0; i < len; i++) {
            array[i] = b[i];
        }
    }

二、桶排序

概念

划分多个范围相同的区间,每个子区间自排序,最后合并

  • 桶排序是计数排序的扩展版本,计数排序:每个桶只存储单一键值

  • 桶排序: 每个桶存储一定范围的数值,确定桶的个数和范围

  • 将待排序数组中的元素映射到各个对应的桶中,对每个桶进行排序

  • 最后将非空桶中的元素逐个放入原序列中

在这里插入图片描述

代码
    public static void bucketSort(int[] array){

        // 计算最大值与最小值
        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for(int i = 0; i < array.length; i++){
            max = Math.max(max, array[i]);
            min = Math.min(min, array[i]);
        }

        // 计算桶的数量
        int bucketNum = (max - min) / array.length + 1;
        ArrayList<ArrayList<Integer>> bucketArr = new ArrayList<>(bucketNum);
        for(int i = 0; i < bucketNum; i++){
            bucketArr.add(new ArrayList<Integer>());
        }

        // 将每个元素放入桶
        for(int i = 0; i < array.length; i++){
            int num = (array[i] - min) / (array.length);
            bucketArr.get(num).add(array[i]);
        }

        // 对每个桶进行排序
        for(int i = 0; i < bucketArr.size(); i++){
            Collections.sort(bucketArr.get(i));
        }

        // 将桶中的元素赋值到原序列
        int index = 0;
        for(int i = 0; i < bucketArr.size(); i++){
            for(int j = 0; j < bucketArr.get(i).size(); j++){
                array[index++] = bucketArr.get(i).get(j);
            }
        }
    }

三、基数排序

概念

  • 基数排序是一种非比较型整数排序算法

  • 将整数按位数切割成不同的数字,然后按每个位数分别比较

  • 使用场景:按位分割进行排序,适用于大数据范围排序,打破了计数排序的限制

  • 稳定性:稳定

  • 按位分割技巧:arr[i] / digit % 10,其中digit为10^n。

在这里插入图片描述

1.LSD排序法(最低位优先法)

  • 从最低位向最高位依次按位进行计数排序。

  • 进出的次数和最大值的位数有关

  • 桶可以用队列来表示

  • 数组的每个元素都是队列

在这里插入图片描述

  • 1.先遍历找到最大值
  • 2.求出最高位

在这里插入图片描述

    public static void radixSortR(int[] array) {
        //10进制数,有10个桶,每个桶最多存array.length个数
        int[][] bucket = new int[10][array.length];
        //桶里面要存的具体数值

        int[] bucketElementCounts = new int[10];
        //用来计算,统计每个桶所存的元素的个数,每个桶对应一个元素

        //1.求出最大数
        int MAX = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > MAX) {
                MAX = array[i];
            }
        }
        //求最大值的位数,先变成字符串,求字符串长度
        int MAXCount = (MAX + "").length();
        //最大位数的个数,进行几次计数排序
        for (int i = 0; i < MAXCount; i++) {//i代表第几次排序
            //放进桶中
            for (int k = 0; k < array.length; k++) {
                //k相当于遍历待排数值
                //array[k] /(int) Math.pow(10, i)%10 求出每次要比较位的数
                //求的是个位,并且是对应趟数的个位
                int value = (array[k] / (int) Math.pow(10, i)) % 10;
                //根据求出的位数,找到对应桶,放到对应桶的位置
                bucket[value][bucketElementCounts[value]] = array[k];
                //不管value 为多少,bucketElementCounts[value]的值都为0
                //相当于存到对应桶的0位bucket[value][0]
                bucketElementCounts[value]++; //从0->1
                //对应桶的技术数组开始计数
            }

            //取出每个桶中的元素,赋值给数组
            int index = 0;//array新的下标
            for (int k = 0; k < bucketElementCounts.length; k++) {//遍历每个桶
                if (bucketElementCounts[k] != 0) {//桶里有元素
                    for (int j = 0; j < bucketElementCounts[k]; j++) {//比那里每个桶的元素
                        array[index] = bucket[k][j];
                        index++;
                    }
                }
                bucketElementCounts[k] =0;//每个桶遍历完后,清空每个桶的元素;
            }
        }
    }

2.MSD排序法(最高位优先法)

在这里插入图片描述

  • 从最高位向最低位依次按位进行排序。
  • 按位递归分组收集
  • 1.查询最大值,获取最高位的基数
  • 2.按位分组,存入桶中
  • 3.组内元素数量>1,下一位递归分组
  • 4.组内元素数量=1.收集元素
   /**
     * 基数排序--MSD--递归
     * @param array
     */

    public static void radixSortMSD(int[] array) {
        //1.求出最大数
        int MAX = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > MAX) {
                MAX = array[i];
            }
        }
        //求最大值的位数,先变成字符串,求字符串长度
        int MAXCount = (MAX + "").length();
        // 计算最大值的基数
        int radix = new Double(Math.pow(10, MAXCount - 1)).intValue();

        int[] arr = msdSort(array, radix);
        System.out.println(Arrays.toString(arr));
    }
    public static int[] msdSort(int[] arr, int radix){
        // 递归分组到个位,退出
        if (radix <= 0) {
            return arr;
        }
        // 分组计数器
        int[] groupCounter = new int[10];

        // 分组桶
        int[][] groupBucket = new int[10][arr.length];

        for (int i = 0; i < arr.length; i++) {
            // 找分组桶位置
            int position = arr[i] / radix % 10;
            // 将元素存入分组
            groupBucket[position][groupCounter[position]] = arr[i];
            // 当前分组计数加1
            groupCounter[position]++;
        }

        int index = 0;
        int[] sortArr = new int[arr.length];


        // 遍历分组计数器
        for (int i = 0; i < groupCounter.length; i++) {
            // 组内元素数量>1,递归分组
            if (groupCounter[i] > 1) {
                int[] copyArr = Arrays.copyOf(groupBucket[i], groupCounter[i]);
                // 递归分组
                int[] tmp = msdSort(copyArr, radix / 10);
                // 收集递归分组后的元素
                for (int j = 0; j < tmp.length; j++) {
                    sortArr[index++] = tmp[j];
                }
            } else if (groupCounter[i] == 1) {
                // 收集组内元素数量=1的元素
                sortArr[index++] = groupBucket[i][0];
            }
        }
        return sortArr;
    }

基数排序VS基数排序VS桶排序

  • 都是非比较型排序

  • 三种排序算法都利用了桶的概念

    1.计数排序:每个桶只存储单一键值;

    2.基数排序:根据键值的每位数字来分配桶

    3.桶排序: 每个桶存储一定范围的数值;

点击移步博客主页,欢迎光临~

偷cyk的图

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/176583.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux:进度条(小程序)以及git三板斧

Linux小程序&#xff1a;进度条 在实现小程序前我们要弄清楚&#xff1a; 1.缓冲区&#xff1b; 2.回车与换行。 缓冲区&#xff1a; 分别用gcc来编译下面两个程序&#xff1a; 程序一&#xff1a; #include <stdio.h> int main() { printf("hello Makefil…

剧情继续:马斯克曝出OpenAI前员工举报信,董事会与奥特曼谈判回归

丰色 发自 凹非寺 量子位 | 公众号QbitAI 经过4天的极限拉扯、反转再反转&#xff0c;奥特曼有可能重新回归了。 据知情人士透露&#xff0c;OpenAI董事会正与奥特曼进行一场“富有成效”的新谈判。 如果奥特曼回到OpenAI&#xff0c;他将继续担任CEO。 与此同时&#xff0c…

【MybatisPlus】简介与使用

MyBatisPlus 1.简介 MyBatisPlus&#xff08;简称MP&#xff09;是一个MyBatis的增强工具&#xff0c;在MyBatis的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生 官网&#xff1a;https://baomidou.com/ MyBatis-Plus特性&#xff1a; 无侵入&#xff1a;只…

一文深入理解Linux进程间通信

一、进程间通信的本质 什么是进程间通信&#xff1f;为什么要有进程间通信&#xff1f; 为什么能进程间通信&#xff1f; 1.1 为什么要通信 我们先拿人来做个类比&#xff0c;人与人之间为什么要通信&#xff0c;有两个原因。首先是因为你有和对方沟通的需求&#xff0c;如…

常用的工作资料怎么在电脑上记录呢?

在现代工作中&#xff0c;我们经常需要记录各种各样的工作资料&#xff0c;例如会议记录、项目计划、待办事项等等。传统的纸质笔记本虽然方便携带&#xff0c;但难以整理和检索。而在电脑上直接记录常用的工作资料&#xff0c;在记录、整理、查看、使用等方面都是更为高效、便…

什么是搜索相关性?AI如何驱动搜索相关性?

训练数据驱动机器学习&#xff0c;机器学习促进丰富的人机交互体验。在快速迭代的互联网时代&#xff0c;我们不断被各种广告铺盖&#xff0c;甚至经常细思极恐&#xff0c;“天呐&#xff0c;小红书怎么知道我面膜没了。”这都是算法和机器学习的鬼斧神工洞察着用户的搜索意图…

使用Microsoft Dynamics AX 2012 - 4. 销售和配送

销售和分销的主要职责是为客户提供您的商品和服务。为了完成这项任务&#xff0c;销售和分销需要通过分拣、运输和开具发票来处理销售订单&#xff0c;从而管理客户的材料需求。 销售和配送业务流程 在我们开始详细介绍之前&#xff0c;下面几行概述了销售和配送中的业务流程…

Imaris 卡退,是不是缓存盘没有设置好?

必须记录一下&#xff0c;从Imaris哔哩哔哩官方视频上学到的&#xff0c;如何设置缓存位置&#xff0c;尤其是做3D视频的时候。 但是隔一段时间就忘记&#xff0c;找不到当时的哔哩哔哩视频 这里记一下 如果是空间比较小的C盘&#xff0c;可以改成一个空间大一点的位置。 把缓…

vue3.0 + qiankun遇到的问题

进入子应用再回到主应用切换动态路由时 TypeError: Cannot read properties of undefined (reading ‘appWrapperGetter’) application ‘plat’ died in status UNMOUNTING: instance.$destroy is not a function 第一个报错是因为子应用切走时没有销毁 vue的实例&#xff0…

React中封装echarts图表组件以及自适应窗口变化

文章目录 前言环境代码接口使用效果后言 前言 hello world欢迎来到前端的新世界 &#x1f61c;当前文章系列专栏&#xff1a;react.js &#x1f431;‍&#x1f453;博主在前端领域还有很多知识和技术需要掌握&#xff0c;正在不断努力填补技术短板。(如果出现错误&#xff0c;…

自动化脚本不稳定,原来是软件弹窗惹的祸,2个方法解决!

很多同学在学习 App 自动化或者在项目中落地实践 App 自动化时&#xff0c;会发现编写的自动化脚本无缘无故的执行失败、不稳定。 而导致其问题很大原因是因为应用的各种弹窗&#xff08;升级弹窗、使用过程提示弹窗、评价弹窗等等&#xff09;&#xff0c;比如这样的&#xff…

sizeof和strlen的区别

目录 一、 sizeof 二、 strlen 三、 sizeof 和 strlen的对比 一、 sizeof 在学习操作符的时候&#xff0c;我们学习了 sizeof &#xff0c; sizeof 计算变量所占内存内存空间大小的&#xff0c;单位是字节&#xff0c;如果操作数是类型的话&#xff0c;计算的是使⽤类型创…

No such module ‘FacebookCore‘

在下面的地方添加这个库

算法——滑动窗口(Sliding Window)

一、背景知识 滑动窗口算法&#xff08;Sliding Window&#xff09;&#xff1a; 在给定数组 / 字符串上维护一个固定长度或不定长度的窗口。可以对窗口进行滑动操作、缩放操作&#xff0c;以及维护最优解操作。题型一&#xff1a;固定长度题型二&#xff1a;不固定长度 二、例…

【Java】智慧工地管理系统源代码,支持二次开发,SaaS模式

智慧工地系统围绕工程现场人、机、料、法、环及施工过程中质量、安全、进度、成本等各项数据满足工地多角色、多视角的有效监管,实现工程建设管理的降本增效。 一、行业现状 1、施工现场管理难&#xff1a;安全事故频发&#xff0c;人工巡检难度大&#xff0c;质量进度协同难等…

一文让你上手Linux常用命令(考前十分钟快速突击+零基础阅读)

文章目录 前言Linux 常用命令1. 基本操作lscdpwd 2. 对文件的操作touchcatechovim 3. 对目录的操作mkdirrm 4. 移动文件 / 目录的操作cpmv 5. 总结基本操作6. 必不可少的实用操作mangreppsnetstat 总结 前言 本文内容为 Linux 的一些超常用命令, 内容不多且十分实用, 这些命令…

前端开发学习 (二) 事件修饰符、系统命令

其实&#xff0c;我们上一章的时候就已经说过了一些系统指令&#xff0c;这里详细介绍一下 一、v-on的事件修饰符 事件作用click点击时触发submit表单被提交时触发input输入框发生改变时触发keyup按键松开时触发keydown按键按下时触发mouseover鼠标悬停触发mouseout当鼠标移开…

Python基础教程: sorted 函数

嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 sorted 可以对所有可迭代的对象进行排序操作&#xff0c; sorted 方法返回的是一个新的 list&#xff0c;而不是在原来的基础上进行的操作。 从新排序列表。 &#x1f447; &#x1f447; &#x1f447; 更多精彩机密、教程…

数字IC基础:有符号数和无符号数加、减法的Verilog设计

相关阅读 数字IC基础https://blog.csdn.net/weixin_45791458/category_12365795.html?spm1001.2014.3001.5482 本文是对数字IC基础&#xff1a;有符号数和无符号数的加减运算一文中的谈到的有符号数加减法的算法进行Verilog实现&#xff0c;有关算法细节请阅读原文&#xff0…

一个月B站涨粉200万,品牌号不可错过的吸粉秘籍

越来越多品牌为了持续在B站营销而创建品牌官方账号&#xff0c;发布原创作品融入B站UP主中&#xff0c;吸引B站用户塑造品牌形象&#xff0c;提高品牌传播度、品牌声量。 据飞瓜数据&#xff08;B站版&#xff09;统计&#xff0c;B站有着超过2万个品牌号&#xff0c;本篇文章…