数据结构与算法之排序算法-(计数,桶,基数排序)

news2025/2/19 7:26:00

排序算法是数据结构与算法中最基本的算法之一,其作用就是将一些可以比较大小的数据进行有规律的排序,而想要实现这种排序就拥有很多种方法~

📚 非线性时间比较类

那么我将通过几篇文章,将排序算法中各种算法细化的,详尽的为大家呈现出来:

📕 插入类排序:数据结构与算法之排序算法-插入排序-CSDN博客

📖 直接插入排序

📖 希尔排序

📕 交换类排序:数据结构与算法之排序算法-快速排序(分治)-CSDN博客

📖 冒泡排序

📖 冒泡排序-优化

📖 快速排序(Hoare,挖坑法,前后指针法)

📖 快速排序-优化

📕 选择类排序:数据结构与算法之排序算法-选择排序-CSDN博客

📖 简单选择排序

📖 堆排序

📕 归并类排序:数据结构与算法之排序算法-归并排序-CSDN博客

📖 归并排序

📚 线性时间非比较

📕 非比较类排序:[本篇]

📖 计数排序

📖 桶排序

📖 基数排序

一、计数排序

稳定性:稳定

时间复杂度:O(n + m)

额外空间复杂度:O(n + m)

大家应该也注意到了,这次学习到的排序算法,不仅具有稳定性,时间复杂度竟然还趋近O(n)!这是相当快的一种排序算法了。

那么为什么它能达到这么优秀的时间复杂度呢?主要就是因为它并不需要对元素之间进行比较~那么有人可能就要发出疑问,不进行比较又如何知道元素与元素间的大小关系呢?

① 计数排序

📚 算法思想

计数排序的基本思想把原数组元素作为数组的下标,创建一个临时数组 arr,使得 arr 至少能将原数组中所有数据都存入数组中。

然后遍历原数组,将遍历到的元素与 arr 下标进行匹配,并使 arr[index]++,代表该数字出现的次数 +1,而将数组遍历结束后,arr 从 start 下标到 end 下标存储的数据正好由下标默认排序好了,并且数据也准确的存到了正确位置~

了解了计数排序的基本思想后,大家或许也知道了为什么它的速度如此之快,相应的,大家应该也能理解为什么它没有"快速排序","归并排序"那么实用了,那就是"额外空间复杂度太高"

图示

📖 代码示例

    public static void countingSort(int[] array) {
        int max = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] > max) {
                max = array[i];
            }
        }
        int[] arr = new int[max + 1];
        for (int i = 0; i < array.length; i++) {
            int index = array[i];
            arr[index]++;
        }
        int k = 0;
        for (int i = 0; i < arr.length; i++) {
            while (arr[i] != 0) {
                array[k] = i;
                arr[i]--;
                k++;
            }
        }
    }

② 计数排序(优化)

上述代码中,我们简单实现了计数排序,但是这样是有缺点的

📕 当数组中元素过大:如 [5000,5005,5010],如果创建一个大小为 5011 的数组,那么浪费的空间就会特别大。

📕 当数组中存在负数:如 [1,2,3,-1],创建数组后,是搜索不到 ' -1 ' 下标的。

📚 算法思想

在原来的基础上,同时算出数组中的最小值,创建一个大小为[max - min + 1]的数组,这样就能有效的降低额外空间的损耗。

并且放入和取出元素时,寻找的下标也相应变成 arr[index] - min ,这样就能够彻底避免访问下标小于0的非法访问。

📖 代码示例

    public static void countingSort(int[] array) {
        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];
            }
        }
        int[] arr = new int[max - min + 1];
        for (int i = 0; i < array.length; i++) {
            int index = array[i] - min;
            arr[index]++;
        }
        int k = 0;
        for (int i = 0; i < arr.length; i++) {
            while (arr[i] != 0) {
                array[k] = i + min;
                arr[i]--;
                k++;
            }
        }
    }

③ 效率测试

顺便一提,快速排序达到的速度为40ms左右,归并排序达到的速度为30ms左右~

二、桶排序

稳定性:稳定

时间复杂度:O(n)

额外空间复杂度:O(m)

上面的计数排数,很快倒是很快,但是它也有相应的缺点

📕 无法对浮点型数据进行排序,因为无法通过浮点型数据查找对应下标

这个算法属于计数排序的一种升级版,它的思想和计数排序类似,也是通过数据的值进行分类。

但它和计数排序也有些不同

📕 它并没有通过数据的值来直接对应下标,而是通过创建一些"桶",并且为它们设定"区间",从而通过数据查找对应区间,这样就能够避免"浮点数非法查找下标"的问题了。

① 桶排序

📚 算法思想

桶排序的基本思想根据原数组的最大值 max 和最小值 min 来划分区间,由这些区间来创造一些"桶"。而每一个桶代表一个区间范围,里面可以承载一个或多个元素。

创建好"桶"后,遍历原数组,将数组中的数据放到对应区间的桶中,然后再分别将桶中的元素排序,这样排好序后,就能够得到我们最终想要的有序数组了。

图示

📖 代码示例

    public static double[] bucketSort(double[] array) {
        //取最大值和最小值,并求出差值
        int len = array.length;
        double max = array[0];
        double min = array[0];
        for (int i = 1; i < len; i++) {
            max = Math.max(array[i], max);
            min = Math.min(array[i], min);
        }
        double d = max - min;
        //创建桶
        int bucketNum = len;
        ArrayList<LinkedList<Double>> bucketList = new ArrayList<LinkedList<Double>>(bucketNum);
        for(int i = 0;i < bucketNum;i++){
            bucketList.add(new LinkedList<Double>());
        }
        //将数组元素放入桶中
        for(int i = 0;i < len;i++){
            int num = (int)((array[i] - min) * (bucketNum - 1) / d);
            bucketList.get(num).add(array[i]);
        }
        //对每个桶进行排序
        for(int i = 0;i < bucketList.size();i++){
            Collections.sort(bucketList.get(i));
        }
        double[] sortArr = new double[len];
        int index = 0;
        for(LinkedList<Double> list:bucketList){
            for(double element: list){
                sortArr[index++] = element;
            }
        }
        return sortArr;
    }

三、基数排序

稳定性:稳定

时间复杂度:O(n * k)

额外空间复杂度:O(n * k)

① 基数排序

📚 算法思想

基数排序的基本思想基数排序的算法思想是,将整数按照位数分别切割成不同的数字。

当每次将数组中的数据按位数分割结束后,分别放入以位数为单位的"桶"中。

然后遍历桶,按照顺序将元素取出,再重新进行分割,入桶等操作,直到分割位数的次数达到了数组中位数最高的元素的限制,排序结束。

📖 代码示例

        public static int[] radioSort(int[] arr) {
        if(arr == null || arr.length < 2) return arr;
        int n = arr.length;
        int max = arr[0];
        // 找出最大值,计算最大值是几位数
        for (int i = 1; i < n; i++) {
            if(max < arr[i]) max = arr[i];
        }
        int num = 1;
        while (max / 10 > 0) {
            num++;
            max = max / 10;
        }
        // 创建10个桶
        ArrayList<LinkedList<Integer>> bucketList = new ArrayList<>(10);
        for (int i = 0; i < 10; i++) {
            bucketList.add(new LinkedList<Integer>());
        }
        // 进行排序
        for (int i = 1; i <= num; i++) {
            for (int j = 0; j < n; j++) {
                int radio = (arr[j] / (int)Math.pow(10,i-1)) % 10;
                bucketList.get(radio).add(arr[j]);
            }
            int k = 0;
            for (int j = 0; j < 10; j++) {
                for (Integer t : bucketList.get(j)) {
                    arr[k++] = t;
                }
            }
        }
        return arr;
    }

那么这篇关于计数排序,桶排序,基数排序的文章到这里就结束啦,作者能力有限,如果有哪里说的不够清楚或者不够准确,还请各位在评论区多多指出,我也会虚心学习的,我们下次再见啦

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

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

相关文章

MATLAB图像处理:图像特征概念及提取方法HOG、SIFT

图像特征是计算机视觉中用于描述图像内容的关键信息&#xff0c;其提取质量直接影响后续的目标检测、分类和匹配等任务性能。本文将系统解析 全局与局部特征的核心概念&#xff0c;深入讲解 HOG&#xff08;方向梯度直方图&#xff09;与SIFT&#xff08;尺度不变特征变换&…

kibana es 语法记录 elaticsearch

目录 一、认识elaticsearch 1、什么是正向索引 2、什么是倒排索引 二、概念 1、说明 2、mysql和es的对比 三、mapping属性 1、定义 四、CRUD 1、查看es中有哪些索引库 2、创建索引库 3、修改索引库 4、删除索引库 5、新增文档 6、删除文档 5、条件查询 一、认识…

手写一个Java Android Binder服务及源码分析

手写一个Java Android Binder服务及源码分析 前言一、Java语言编写自己的Binder服务Demo1. binder服务demo功能介绍2. binder服务demo代码结构图3. binder服务demo代码实现3.1 IHelloService.aidl3.2 IHelloService.java&#xff08;自动生成&#xff09;3.3 HelloService.java…

【动态规划篇】:当回文串遇上动态规划--如何用二维DP“折叠”字符串?

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;动态规划篇–CSDN博客 文章目录 一.回文串类DP核心思想&#xff08;判断所有子串是否是回文…

Windows 安装 GDAL 并配置 Rust-GDAL 开发环境-1

Rust-GDAL 是 Rust 语言的 GDAL&#xff08;Geospatial Data Abstraction Library&#xff09; 绑定库&#xff0c;用于处理地理数据。由于 GDAL 依赖较多&#xff0c;在 Windows 上的安装相对复杂&#xff0c;本文档将介绍如何安装 GDAL 并配置 Rust-GDAL 的开发环境。 1. 检…

第1期 定时器实现非阻塞式程序 按键控制LED闪烁模式

第1期 定时器实现非阻塞式程序 按键控制LED闪烁模式 解决按键扫描&#xff0c;松手检测时阻塞的问题实现LED闪烁的非阻塞总结补充&#xff08;为什么不会阻塞&#xff09; 参考江协科技 KEY1和KEY2两者独立控制互不影响 阻塞&#xff1a;如果按下按键不松手&#xff0c;程序就…

开源语音克隆项目 OpenVoice V2 本地部署

#本机环境 WIN11 I5 GPU 4060ti 16G 内存 32G #开始 git clone https://github.com/myshell-ai/OpenVoice.git conda create -n opvenv python3.9 -y conda activate opvenv pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/…

DeepSeek大模型一键部署解决方案:全平台多机分布式推理与国产硬件优化异构计算私有部署

DeepSeek R1 走红后&#xff0c;私有部署需求也随之增长&#xff0c;各种私有部署教程层出不穷。大部分教程只是简单地使用 Ollama、LM Studio 单机运行量化蒸馏模型&#xff0c;无法满足复杂场景需求。一些操作配置也过于繁琐&#xff0c;有的需要手动下载并合并分片模型文件&…

如何利用PLM软件有效地推进制造企业标准化工作?

在智能制造浪潮的推动下&#xff0c;中国制造业正面临从“规模扩张”向“质量提升”的关键转型。工信部数据显示&#xff0c;85%的制造企业在产品研发、生产过程中因标准化程度不足导致效率损失超20%&#xff0c;而标准化水平每提升10%&#xff0c;企业综合成本可降低5%-8%。如…

环境影响评价(EIA)中,土地利用、植被类型及生态系统图件的制作

在环境影响评价&#xff08;EIA&#xff09;中&#xff0c;土地利用、植被类型及生态系统图件的制作需依据科学、法规和技术规范&#xff0c;以确保数据的准确性和图件的规范性。以下是主要的制作依据&#xff1a; 1. 法律法规与政策依据 《中华人民共和国环境影响评价法》 明确…

更高效实用 vscode 的常用设置

VSCode 可以说是文本编辑神器, 不止程序员使用, 普通人用其作为文本编辑工具, 更是效率翻倍. 这里分享博主对于 VSCode 的好用设置, 让 VSCode 如虎添翼 进入设置 首先进入设置界面, 后续都在这里进行配置修改 具体设置 每项配置通过搜索关键字, 来快速定位配置项 自动保存…

【异或数列——博弈论】

题目 思路 异或和为0&#xff08;即每一位都有偶数个1&#xff09;&#xff1a;平局最高有效位只有唯一的1&#xff1a;先手必胜最高有效位有奇数个1&#xff0c;偶数个0&#xff1a;先手必胜 若先选1产生优势&#xff0c;则剩下偶数个1&#xff0c;偶数个0&#xff1a;对手选…

草图绘制技巧

1、点击菜单栏文件–》新建–》左下角高级新手切换–》零件&#xff1b; 2、槽口&#xff1a;直槽口&#xff0c;中心点槽口&#xff0c;三点源槽口&#xff0c;中心点圆弧槽口&#xff1b; 3、草图的约束&#xff1a;需要按住ctrl键&#xff0c;选中两个草图&#xff0c;然后…

Spring Boot中如何自定义Starter

文章目录 Spring Boot中如何自定义Starter概念和作用1. 概念介绍2. 作用和优势2.1 简化依赖管理2.2 提供开箱即用的自动配置2.3 标准化和模块化开发2.4 提高开发效率2.5 提供灵活的配置覆盖3. 应用场景创建核心依赖1. 确定核心依赖的作用2. 创建 starter-core 模块2.1 依赖管理…

内容中台构建高效数字化内容管理新范式

内容概要 在数字化转型浪潮中&#xff0c;高效的内容管理能力已成为企业构建核心竞争力的关键要素。通过动态发布引擎、元数据智能分类与跨平台协作机制&#xff0c;企业能够实现内容的实时触达与精准分发&#xff0c;同时确保知识资产在多终端环境下的无缝适配与安全共享。这…

PyQt组态软件 拖拽设计界面测试

PyQt组态软件测试 最近在研究PyQt,尝试写个拖拽设计界面的组态软件&#xff0c;目前实现的功能如下&#xff1a; 支持拖入控件&#xff0c;鼠标拖动控件位置 拖动控件边缘修改控件大小支持属性编辑器&#xff0c;修改当前选中控件的属性 拖动框选控件&#xff0c;点选控件 控…

深度学习R4周:LSTM-火灾温度预测

&#x1f368; 本文为&#x1f517;365天深度学习训练营中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 任务&#xff1a; 数据集中提供了火灾温度&#xff08;Tem1&#xff09;、一氧化碳浓度&#xff08;CO 1&#xff09;烟雾浓度&#xff08;Soot 1&#xff09;…

Datawhale 数学建模导论二 笔记1

第6章 数据处理与拟合模型 本章主要涉及到的知识点有&#xff1a; 数据与大数据Python数据预处理常见的统计分析模型随机过程与随机模拟数据可视化 本章内容涉及到基础的概率论与数理统计理论&#xff0c;如果对这部分内容不熟悉&#xff0c;可以参考相关概率论与数理统计的…

UIView 与 CALayer 的联系和区别

今天说一下UIView 与 CALayer 一、UIView 和 CALayer 的关系 在 iOS 开发中&#xff0c;UIView 是用户界面的基础&#xff0c;它负责处理用户交互和绘制内容&#xff0c;而 CALayer 是 UIView 内部用于显示内容的核心图层&#xff08;Layer&#xff09;。每个 UIView 内部都有…

一键安装教程

Maven 安装 右键 以管理员身份运行点击 下一步安装完成后会同步配置环境变量打开 cmd, 输入 mvn 查看mvn版本修改 maven 本地仓库地址 见图三, 本地新建文件夹&#xff0c;修改为你本地文件夹地址 Redis 安装 右键 以管理员身份运行点击 下一步会安装到选择的文件夹下 JAVA\R…