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

news2024/11/14 21:05:55

文章目录

  • 计数排序+桶排序+基数排序
    • 一、计数排序
          • 概念:
          • 写法一:
          • 写法二:
    • 二、桶排序
        • 概念
        • 代码
    • 三、基数排序
      • 概念
      • 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的图

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C++语法知识点-vector+子数组

C语法知识点-vector子数组 一维数组定义无参数有参数迭代器扩容操作reserve 二维数组 vector 定义创建m*n的二维vectorvector< vector<int> > v(m, vector<int>(n) ) 初始化定义vector常用函数的实例分析访问操作resize 函数push _back ( )pop_back()函数siz…

宣传技能培训1——《新闻摄影技巧》光影魔法:理解不同光线、角度、构图的摄影效果,以及相机实战操作 + 新闻摄影实例讲解

新闻摄影技巧 写在最前面摘要 构图与拍摄角度景别人物表情与叙事远景与特写 构图与拍摄角度案例 主体、陪体、前景、背景强调主体利用前景和背景层次感的创造 探索新闻摄影中的构图技巧基本构图技巧构图技巧的应用实例实例分析1. 黄金分割和九宫格2. 三角型构图3. 引导线构图4.…

2 使用React构造前端应用

文章目录 简单了解React和Node搭建开发环境React框架JavaScript客户端ChallengeComponent组件的主要结构渲染与应用程序集成 第一次运行前端调试将CORS配置添加到Spring Boot应用使用应用程序部署React应用程序小结 前端代码可从这里下载&#xff1a; 前端示例 后端使用这里介…

unity shaderGraph实例-可交互瀑布

不要问我水在哪里&#xff0c;你自己相像这是一个瀑布&#xff0c;瀑布的效果我还不会做 效果展示 整体结构 这里片元着色器最后输出的baseColor应该是黑色&#xff0c;白色为错误。 各区域内容 区域1 计算球到瀑布的距离&#xff0c;然后减去一个值&#xff0c;实现黑色区域…

【小黑送书—第九期】>>重磅!这本30w人都在看的Python数据分析畅销书:更新了!

想学习python进行数据分析&#xff0c;这本《利用python进行数据分析》是绕不开的一本书。目前该书根据Python3.10已经更新到第三版。 Python 语言极具吸引力。自从 1991 年诞生以来&#xff0c;Python 如今已经成为最受欢迎的解释型编程语言。 pandas 诞生于2008年。它是由韦…

【亚太杯前两问论文】2023年第十三届APMCM亚太地区大学生数学建模竞赛——(文末领取方式)

2023年第十三届APMCM亚太地区大学生数学建模竞赛——论文无偿分享&#xff01;&#xff01;&#xff01; C题前两问论文代码已出&#xff0c;其他赛题及后续论文代码会持续更新。 祝各位小伙伴都能在比赛中发挥出色&#xff0c;取得心仪的成绩呦&#xff01;一起加油&#xff…

使用Arrays.Sort并定制Comparator排序解决合并区间

合并区间-力扣算法题56题 以数组 intervals 表示若干个区间的集合&#xff0c;其中单个区间为 intervals[i] [starti, endi] 。请你合并所有重叠的区间&#xff0c;并返回 一个不重叠的区间数组&#xff0c;该数组需恰好覆盖输入中的所有区间 。 示例 1&#xff1a; 输入&am…

姿态传感器——MPU6050

1、MPU6050介绍 MPU6050是由三个陀螺仪和三个加速度传感器组成的6轴运动处理组件&#xff0c;是一款六轴&#xff08;三轴加速度三轴角速度&#xff08;陀螺仪&#xff09;&#xff09;传感器。 内部主要结构 陀螺仪、加速度计、数字运动处理器DMP&#xff08;Digital Moti…

uniapp 轮播图(含组件封装,自动注册全局组件)

效果预览 组件封装 src\components\SUI_Swiper.vue 可参考官网配置更多属性 swipernavigator <script setup lang"ts"> import { ref } from vue defineProps({config: Object, })const activeIndex ref(0) const change: UniHelper.SwiperOnChange (e) &…

msvcp120.dll丢失是什么意思,哪个修复方法最简单

在计算机使用过程中&#xff0c;我们经常会遇到一些错误提示&#xff0c;其中之一就是“找不到msvcp120.dll”。这个错误通常发生在运行某些程序或游戏时&#xff0c;它会导致程序无法正常启动或运行。那么&#xff0c;这个错误提示到底是什么意思呢&#xff1f;为了解决这个问…

当老师应该选文科还是理科

教育不断发展和改革&#xff0c;教师职业的选择也越来越受到关注。许多人在选择专业时都会考虑成为一名教师&#xff0c;但对于选择文科还是理科却感到困惑。本文将探讨当老师应该选文科还是理科。 文科注重的是人文素养和社会科学方面的知识&#xff0c;而理科则注重自然科学和…

springcloud超市管理系统源码

技术说明&#xff1a; jdk1.8&#xff0c;mysql5.7&#xff0c;idea&#xff0c;vscode springcloud springboot mybatis vue elementui mysql 功能介绍&#xff1a; 后台管理&#xff1a; 统计分析&#xff1a;查看用户&#xff0c;商品&#xff0c;销售数量&#xff1b;…

王道p150 20.将给定的表达式树转化为等价的中缀表达式(通过括号反应操作符的计算次序)

本题代码如下 void btreetoexp(tree t, char deep) {if (t NULL)return;else if (t->lchild NULL && t->rchild NULL)printf("%c", t->data);//输出操作数&#xff0c;不加括号else {if (deep > 1)printf("(");btreetoexp(t->l…

职场Excel:求和家族,不简单

说到excel函数&#xff0c;很多人第一时间想到的就是求和函数sum。作为excel入门级函数&#xff0c;sum的确是小白级的&#xff0c;以至于很多人对求和函数有点“误解”&#xff0c;觉得求和函数太简单了。 但是&#xff0c;你可能不知道&#xff0c;sum只是excel求和家族里的一…

阿里入局鸿蒙!鸿蒙原生应用再添两员新丁

今日HarmonyOS微博称&#xff0c;阿里钉钉、蚂蚁集团旗下的移动开发平台mPaaS与华为达成合作&#xff0c;宣布启动鸿蒙原生应用的开发&#xff01;相关应用将以原生方式适配#HarmonyOS NEXT#系统。 #HarmonyOS#市场或迎来爆发式增长&#xff01; 阿里钉钉 阿里钉钉与华为达成合…

231123 刷题日报-动态规划

今天主要看了DP&#xff0c;前几天频繁遇到DP打击有点大。。 1. 0-1背包问题 要点&#xff1a; a. 三部曲&#xff1a; 1. 状态和选择 状态&#xff1a;物品序号、背包容量 选择&#xff1a;放、不放 2. dp数组定义、base case dp[i][w] 对于前i个物品&#xff0c;当前背包…

简单的用Python采集股票数据,保存表格后分析历史数据

前言 字节跳动如果上市&#xff0c;那么钟老板将成为我国第一个世界首富 趁着现在还没上市&#xff0c;咱们提前学习一下用Python分析股票历史数据&#xff0c;抱住粗大腿坐等起飞~ 好了话不多说&#xff0c;我们直接开始正文 准备工作 环境使用 Python 3.10 解释器Pychar…

检验LIS系统:医院信息管理的重要组成部分

检验LIS系统源码&#xff0c;云LIS系统源码 云LIS系统是医院信息管理的重要组成部分之一&#xff0c;集申请、采样、核收、计费、检验、审核、发布、质控、查询、耗材控制等检验科工作为一体的网络管理系统。LIS系统不仅是自动接收检验数据&#xff0c;打印检验报告&#xff0c…

WordPress网站如何修复数千个帖子的SEO错误

在本教程中&#xff0c;我们将向您展示如何解决您经常犯的SEO错误。 最好的是您不必花费太多时间&#xff0c;因为您不需要打开并编辑每个帖子。 相反&#xff0c;我们将向您展示如何使用 WordPress 内的电子表格来修复 WordPress 帖子的 SEO。 在这里&#xff0c;我们为您提…

机器学习---最大似然估计和贝叶斯参数估计

1. 估计 贝叶斯框架下的数据收集&#xff0c;在以下条件下我们可以设计一个可选择的分类器 : P(wi) (先验)&#xff1b;P(x | wi) (类条件密度) 但是。我们很少能够完整的得到这些信息! 从一个传统的样本中设计一个分类器&#xff1a; ①先验估计不成问题 ②对类条件密度…