【算法】计数排序、桶排序、基数排序

news2025/4/21 7:26:04

算法系列八:非比较排序

一、计数排序

1.实现

1.1步骤

1.2代码

2.性质

2.1稳定性

2.1.1从前往后前始版:

2.1.2从后往前末始版:

2.2复杂度

2.2.1时间复杂度

2.2.2空间复杂度

二、桶排序

1.实现

1.1步骤

1.2代码

2.稳定性

三、基数排序

1.原理

2.代码


鸽巢原理

鸽子归巢,待排序数据归到有序组群中按大小归进有序组群来排数越大,归到的有序组就在越后的数越小,归到的有序组就在越前的

  • 如果有序组以一个元素一个元素划分的,实现的是元素组归巢排序,即计数排序
  • 如果有序组按范围多个元素为一组划分的,实现的是范围组归巢排序,即桶排序

一、计数排序

1.实现

1.1步骤

  1. 开辟数据范围内的所有元素都有各自对应的元素组巢穴,范围内一共有多少种个数据,就开辟每种个数据都有对应的多大的数组,比如90(max) - 10(min) = 80(种个数据)
  2. 归巢时,通过该数据-数据范围内的最小值得到所归巢的下标,然后在数组元素巢中计数表示归巢
  3. 因为巢内只有一种个数据直接就是有序的,所以所有数据归完巢在巢层面有序时所有数据就已经有序了,最后将它们按顺序地赶出巢加回去即得原来有序的数据


1.2代码

    public static void countSort(int[] array) {
        //1.求当前数据的最大值和最小值
        int minVal = array[0];
        int maxVal = array[0];
        for (int i = 1; i < array.length; i++) {
            if(array[i] < minVal) {
                minVal = array[i];
            }
            if(array[i] > maxVal) {
                maxVal = array[i];
            }
        }

        //2.根据数据最大值和最小值来确定元素组巢穴数组的大小
        int[] count = new int[maxVal-minVal+1];

        //3.遍历原来的数据进行归巢排序
        for (int i = 0; i < array.length; i++) {
            count[array[i]-minVal]++;
        }

        //4.将元素组巢穴里已排好序的数据按顺序写回array
        int index = 0;//重新表示array数组的下标
        for (int i = 0; i < count.length; i++) {
            while (count[i] > 0) {
                array[index] = i+minVal;
                index++;
                count[i]--;
            }
        }
    }
}

2.性质

2.1稳定性

每个数据都归到巢中完成有序时,根据巢中有序来的元素的计数个数,可以将巢改装成装每种个元素有序排的始位置,通过对应顺序遍历原数组将数据正确稳定地放在排好序的各自位置上,能实现稳定的排序,所以计数排序是稳定的排序

2.1.1从前往后前始版:

原本巢中装的是鸽子的计数数量,现在巢里面改装成装种个鸽子从前往后的起始位置进行排序:


2.1.2从后往前末始版:

 巢里面改装成装种个鸽子从后往前的起始位置进行排序:


2.2复杂度

2.2.1时间复杂度

找最大最小值确定范围种个数据遍历原数组用了n原数组数据每个去归巢用了n范围x种个元素巢每个去赶,所以时间复杂度为2n + x,即O(n+x)


2.2.2空间复杂度

范围x种个数据需要开辟x个元素巢的数组,所以空间复杂度为O(x)


二、桶排序

1.实现

1.1步骤

  1. 开辟数据范围内所有元素都有对应的范围数组组巢穴将所有数据入范围组巢穴先进行第一轮巢穴外的排好序,此时巢外已经有序了
  2. 再进行第二轮各自巢穴内的排好序,此时就巢外、巢内都有序所有数据都有序了
  3. 最后按顺序地将它们从数组巢中赶出即得有序的数据


1.2代码

    public static int[] bucketSort(int[] arr) {
        // 边界条件:空数组或单个元素直接返回
        if (arr.length <= 1) {
            return arr.clone();
        }

        // Step 1: 确定数据范围
        int minVal = Integer.MAX_VALUE;
        int maxVal = Integer.MIN_VALUE;
        for (int num : arr) {
            if (num < minVal) minVal = num;
            if (num > maxVal) maxVal = num;
        }

        // 处理所有元素相同的情况
        if (maxVal == minVal) {
            return arr.clone();
        }

        // Step 2: 初始化桶
        int bucketCount = (int) Math.sqrt(arr.length) + 1; // 桶数量=数组长度的平方根(经验值)
        double bucketRange = (double)(maxVal - minVal) / bucketCount;

        List<List<Integer>> buckets = new ArrayList<>(bucketCount);
        for (int i = 0; i < bucketCount; i++) {
            buckets.add(new ArrayList<>());
        }

        // Step 3: 元素分配到桶中
        for (int num : arr) {
            // 计算元素应该属于哪个桶
            int index = (int)((num - minVal) / bucketRange);
            // 处理最大值刚好落在最后一个桶外的情况
            if (index == bucketCount) index--;
            buckets.get(index).add(num);
        }

        // Step 4: 对每个桶内部排序
        for (List<Integer> bucket : buckets) {
            Collections.sort(bucket); // 使用内置排序算法,决定了桶排序的稳定性
        }

        // Step 5: 合并桶
        int[] sortedArr = new int[arr.length];
        int idx = 0;
        for (List<Integer> bucket : buckets) {
            for (int num : bucket) {
                sortedArr[idx++] = num;
            }
        }

        return sortedArr;
    }

2.稳定性

稳定性取决于在第二轮巢内开始排相同大小的元素时所用的排序方法是否具有稳定性


三、基数排序

1.原理

  1. 先进行个位排序,能实现个位一位数有序
  2. 个位有序下,再进行十位优先排序,能实现十位个位两位数有序
  3. 十个位有序下,再进行百位优先排序,能实现百位十位个位三位数有序


2.代码

    public static int[] radixSort(int[] arr) {
        if (arr.length <= 1) {
            return arr.clone();
        }

        // Step 1: 确定最大数的位数
        int maxNum = Integer.MIN_VALUE;
        for (int num : arr) {
            if (num > maxNum) maxNum = num;
        }

        // Step 2: 按每位进行计数排序(从低位到高位)
        int exp = 1; // 从个位开始
        while (maxNum / exp > 0) {
            // 初始化10个数字桶(0-9)
            List<List<Integer>> buckets = new ArrayList<>(10);
            for (int i = 0; i < 10; i++) {
                buckets.add(new ArrayList<>());
            }

            // 按当前位分配到桶中
            for (int num : arr) {
                int digit = (num / exp) % 10; // 提取当前位的数字
                buckets.get(digit).add(num);
            }

            // 重组数组
            int idx = 0;
            for (List<Integer> bucket : buckets) {
                for (int num : bucket) {
                    arr[idx++] = num;
                }
            }

            exp *= 10; // 处理更高位
        }

        return arr;
    }

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

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

相关文章

Halcon应用:相机标定

提示&#xff1a;若没有查找的算子&#xff0c;可以评论区留言&#xff0c;会尽快更新 Halcon应用&#xff1a;相机标定 前言一、Halcon应用&#xff1f;二、应用实战1、图像理解1.1、开始标定 前言 本篇博文主要用于记录学习Halcon中算子的应用场景&#xff0c;及其使用代码和…

【C++ 程序设计】实战:C++ 实践练习题(31~40)

目录 31. 数列&#xff1a;s 1 &#xff0b; 2 &#xff0b; 3 &#xff0b; … &#xff0b; n 32. 数列&#xff1a;s 1 - 2 - 3 - … - n 33. 数列&#xff1a;s 1 &#xff0b; 2 - 3 &#xff0b; … - n 34. 数列&#xff1a;s 1 - 2 &#xff0b; 3 - … &#…

绿幕抠图直播软件-蓝松抠图插件--使用相机直播,灯光需要怎么打?

使用SONY相机进行绿幕抠图直播时&#xff0c;灯光布置是关键&#xff0c;直接影响抠图效果和直播画质。以下是详细的灯光方案和注意事项&#xff1a; 一、绿幕灯光布置核心原则 均匀照明&#xff1a;绿幕表面光线需均匀&#xff0c;避免阴影和反光&#xff08;亮度差控制在0.5…

从外网访问局域网服务器的方法

一、为什么局域网的服务器无法在外网访问&#xff1f; 服务器、电脑之间靠IP地址寻址&#xff0c;目前大部分基于IPV4进行寻址访问。但是因为IPV4的地址数量有限&#xff0c;中国分到的还比较少&#xff0c;所以非常紧缺。 一个解决方案就是在局域网来建立一个内部的网…

机器学习 Day12 集成学习简单介绍

1.集成学习概述 1.1. 什么是集成学习 集成学习是一种通过组合多个模型来提高预测性能的机器学习方法。它类似于&#xff1a; 超级个体 vs 弱者联盟 单个复杂模型(如9次多项式函数)可能能力过强但容易过拟合 组合多个简单模型(如一堆1次函数)可以增强能力而不易过拟合 集成…

交换机与路由器的主要区别:深入分析其工作原理与应用场景

在现代网络架构中&#xff0c;交换机和路由器是两种至关重要的设备。它们在网络中扮演着不同的角色&#xff0c;但很多人对它们的工作原理和功能特性并不十分清楚。本文将深入分析交换机与路由器的主要区别&#xff0c;并探讨它们的工作原理和应用场景。 一、基本定义 1. 交换…

【Oracle专栏】Oracle中的虚拟列

Oracle相关文档&#xff0c;希望互相学习&#xff0c;共同进步 风123456789&#xff5e;-CSDN博客 1.背景 在EXP方式导出时&#xff0c;发现 出现如下提示 EXP-00107: virtual column 不支持&#xff0c;因此采用expdp方式导出。于是本文针对oracle虚拟列进行简单介绍。 2. 相…

2020 年 7 月大学英语四级考试真题(组合卷)——解析版

&#x1f3e0;个人主页&#xff1a;fo安方的博客✨ &#x1f482;个人简历&#xff1a;大家好&#xff0c;我是fo安方&#xff0c;目前中南大学MBA在读&#xff0c;也考取过HCIE Cloud Computing、CCIE Security、PMP、CISP、RHCE、CCNP RS、PEST 3等证书。&#x1f433; &…

大语言模型的训练、微调及压缩技术

The rock can talk — not interesting. The rock can read — that’s interesting. &#xff08;石头能说话&#xff0c;不稀奇。稀奇的是石头能读懂。&#xff09; ----硅谷知名创业孵化器 YC 的总裁 Gar Tan 目录 1. 什么是大语言模型&#xff1f; 2. 语言建模&#xff…

firewall指令

大家好,今天我们继续来了解服务管理,来看看打开或关闭指定端口,那么话不多说,开始吧. 1.打开或者关闭指定端口 在真正的生产环境,往往需要防火墙,但问题来了,如果我们把防火墙打开,那么外部请求数据包就不能跟服务器监听通讯,这时,需要打开指定的端口,比如80,22,8080等. 2.fi…

【MySQL】MySQL表的增删改查(CRUD) —— 上篇

目录 MySQL表的增删改查&#xff08;CRUD&#xff09; 1. 新增&#xff08;Create&#xff09;/插入数据 1.1 单行数据 全列插入 insert into 表名 values(值, 值......); 1.2 单行数据 指定列插入 1.3 多行数据 指定列插入 1.4 关于时间日期&#xff08;datetime&am…

软考高级系统架构设计师-第15章 知识产权与标准化

【本章学习建议】 根据考试大纲&#xff0c;本章主要考查系统架构设计师单选题&#xff0c;预计考3分左右&#xff0c;较为简单。 15.1 标准化基础知识 1. 标准的分类 分类 内容 国际标准&#xff08;IS&#xff09; 国际标准化组织&#xff08;ISO&#xff09;、国际电工…

Spring Boot 整合 DeepSeek 实现AI对话 (保姆及教程)

文章目录 文章目录 前言 一、创建 spring boot 工程 二、申请key 三、修改配置文件 application.properties 四、编写控制器&#xff08;controller&#xff09; 五、运行调试 前言 提示&#xff1a;随着人工智能的不断发展&#xff0c;ai这门技术也越来越重要&#xff0c;很多…

前端与传统接口的桥梁:JSONP解决方案

1.JSONP原理 1.1.动态脚本注入 说明&#xff1a;通过创建 <script> 标签绕过浏览器同源策略 1.2.回调约定 说明&#xff1a;服务端返回 函数名(JSON数据) 格式的JS代码 1.3.自动执行 说明&#xff1a;浏览器加载脚本后立即触发前端预定义的回调函数&#xff08;现代开…

编码器---正交编码器

一、正交编码器定义与核心作用 正交编码器&#xff08;Orthogonal Encoder&#xff09;&#xff0c;又称增量式编码器&#xff0c;是一种通过输出两路相位差90的脉冲信号&#xff08;A相、B相&#xff09;来测量旋转角度、速度和方向的传感器。其核心优势是通过A/B相的脉冲顺序…

开发环境解决浏览器层面跨域问题

适用于开发环境临时调试等情况 新建一个 Chrome 的快捷方式&#xff0c;目标后面跟上&#xff1a; –disable-web-security --disable-gpu --user-data-dir%LOCALAPPDATA%\Google\chromeTemp 打开后会给出不安全的提示

2025年渗透测试面试题总结-拷打题库07(题目+回答)

网络安全领域各种资源&#xff0c;学习文档&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具&#xff0c;欢迎关注。 目录 2025年渗透测试面试题总结-拷打题库07 1. CMS目录扫描的意义 2. 常见网站服务器容器 3. MySQL写入We…

深入理解Linux中的线程控制:多线程编程的实战技巧

个人主页&#xff1a;chian-ocean 文章专栏-Linux 前言&#xff1a; POSIX线程&#xff08;Pthreads&#xff09; 是一种在 POSIX 标准下定义的线程库&#xff0c;它为多线程编程提供了统一的接口&#xff0c;主要用于 UNIX 和类 UNIX 系统&#xff08;如 Linux、MacOS 和 BS…

【条形码识别改名工具】如何批量识别图片条形码,并以条码内容批量重命名,基于WPF和Zxing的开发总结

批量图片条形码识别与重命名系统 (WPF + ZXing)开发总结 项目适用场景 ​​电商商品管理​​:批量处理商品图片,根据条形码自动分类归档​​图书馆系统​​:扫描图书条形码快速建立电子档案​​医疗档案管理​​:通过药品条形码整理医疗图片资料​​仓储管理​​:自动化识…

【C++】 —— 笔试刷题day_22

一、添加字符 题目解析 这道题&#xff0c;给定两个字符串A和B&#xff0c;字符串A的长度要小于B的长度&#xff1b; 现在我们要对A字符串添加字符&#xff0c;使得A字符串长度等于B字符串的长度&#xff0c;并且要求对应位置的字母尽量相等&#xff0c;然后求出来不相等的字符…