计数排序,基数排序,桶排序

目录

计数排序:

基数排序:

桶排序:

计数排序:

计数排序是一种非比较型整数排序算法,特别适用于一定范围内的整数排序。它的核心思想是使用一个额外的数组(称为计数数组)来计算每个值的出现次数,然后根据这些计数信息将所有的数字放到正确的位置上,从而实现排序。

大致流程就是这样的,我会用图和代码的思想给大家讲清楚的:

  1. 确定范围:首先遍历一遍待排序的数组,找出其中最大值和最小值,从而确定数字的范围。这是因为计数排序要求输入数据在一个已知的有限范围内。

  2. 初始化计数数组:创建一个长度为最大值与最小值之差加一的计数数组,并将所有元素初始化为0。计数数组的索引代表原始数组中的数值,值则表示该数值出现的次数。

  3. 计数:再次遍历原始数组,对于每个元素,将计数数组中对应索引的值加一,即统计每个元素出现的次数。

  4. 累加计数:对计数数组进行累加操作,使得计数数组中的每个元素变成小于等于其索引值的所有元素的累计总和。这样,计数数组中的每个位置就表示了在排序后数组中相应数值的起始位置。

  5. 重建数组:最后,从计数数组反向遍历原始数组,根据计数数组的信息将元素放到排序后数组的正确位置上。当把一个元素放到排序后数组时,相应地减少计数数组中该元素的计数,以保持计数的准确性。

第一步:创建一个数组,并且找到其中的最大值和最小值

第二步: 定义一个count数组(最大值 减去 最小值 加一),用来统计每个数字出现的次数

 第三步:遍历count数组,然后按照大小顺序把依次放回array数组里面去(可以理解成覆盖了原数组),最后出来的结果就可以按照大小顺序看到每一个数字出现的多少次

最后出来的结果就是:[1, 1, 2, 3, 4, 5, 5, 6, 8, 9, 9]

public static int[] countSort(int[] array){
        int minval = array[0];
        int maxval = array[0];
        for(int i = 0;i<array.length;i++){
            if(array[i] < minval){
                minval = array[i];
            }
            if(array[i] > maxval){
                maxval = array[i];
            }
        }
        int[] count = new int[maxval-minval+1];
        for(int i = 0;i<array.length;i++){
            int val = array[i];
            count[val-minval]++;
        }
        //遍历计数数组
        int index = 0;
        for(int i = 0;i<count.length;i++){
            while(count[i]>0){
                array[index] = i+minval;
                index++;
                count[i]--;
            }
        }
        return array;
    }

 

时间复杂度:

  • 计数排序的时间复杂度主要由两部分组成:统计每个元素出现次数和根据统计结果重构输出数组。对于n个元素,范围在0到k之间的整数排序,计数排序的时间复杂度为O(n+k)。其中,n是数组长度,k是数组中最大值与最小值的差加1。在最好的情况下(即k接近n或n),时间复杂度接近线性,但在k远大于n时,时间复杂度会显著增长。

空间复杂度:

  • 计数排序需要额外的空间来存储每个元素的计数,这个空间取决于待排序数组中元素的范围。具体来说,需要一个大小为k+1的计数数组,其中k是数组中的最大值与最小值之差加1。因此,空间复杂度为O(k)。如果k与n同数量级,那么空间复杂度也是线性的,即O(n)。

稳定性:

  • 计数排序是一种稳定的排序算法。因为它在统计每个元素的频率之后,按照元素原来的顺序(通过第二个循环从最小元素开始逐个累加计数数组并放回原数组)将元素放回原数组,保证了相同元素的相对位置不会改变。

基数排序:

它的核心思想是将待排序的元素根据其每一位的数值进行分配,这个过程通常从最低有效位(LSD)开始,也可以从最高有效位(MSD)开始,然后按位递进,直到最高位。基数排序利用了分配式排序的策略,也被称为“桶排序”的一种推广。


第一步:首先得有一个数组然后才能对数组进行排序,找到数组中的最大值,确定最大值的位数,比如198就是3位数

第二步:新建一个buckets数组,根据个位十位百位...来存放数据

1.按照个位数排序就是这样的,然后我们按照先进先出的原则拿出来

 

2.此时的buckets数组就是:

 

3.因为最大为2位数,所以我们还得再进行一个十位的比较

4. 按照先进先出的原则拿出来就得到最终结果

private static int getMaxDigits(int[] array){
    int maxnum = array[0];
    for(int num : array){
        if(num > maxnum){
            maxnum = num;
        }
    }
    return (int)Math.log10(maxnum)+1;
}

public static int[] radixSort(int[] array){
    int maxnum = getMaxDigits(array);
    int radix = 10;//基数是10 因为是10进制
    List<Integer>[] buckets = new ArrayList[radix];
    for(int i = 0;i < radix;i++){
        buckets[i] = new ArrayList<>();
    }

    for(int digit = 1;digit <= maxnum;digit++){

        //记得每次要把桶清空
        for (List<Integer> bucket : buckets) {
            bucket.clear();
        }

        for (int num : array) {
            int index = (num / (int)Math.pow(10,digit-1))%10;
            buckets[index].add(num);
        }

        //从桶中收集元素到数组
        int index = 0;
        for(List<Integer> bucket : buckets){
            for(int num : bucket){
                array[index] = num;
                index++;
            }
        }
    }
    return array;
}

 

时间复杂度:

  • 基数排序的时间复杂度主要取决于数字的位数(d,即最大数的位数)和待排序元素的数量(n)。
  • 最好、平均和最坏情况下,基数排序的时间复杂度都是O(d*(n+k)),其中k是基数(通常是10,因为基数排序常用于十进制数)。这意味着排序的总成本是元素数量乘以位数,加上每一轮分配和收集过程中桶的管理开销。当d和k相对于n较小或固定时,基数排序非常高效。

空间复杂度:

  • 空间复杂度主要来自于存储桶(或列表)的需要。基数排序需要额外的空间来存放每个基数下的元素。最坏情况下,每个元素都会进入不同的桶中,因此空间复杂度为O(n+k)。但实际上,由于基数排序是分轮进行的,每轮只需要足够的空间来存放每个桶中的元素,理想情况下空间复杂度可以近似为O(n)。但是,考虑到实际实现中可能会为每一轮都分配桶空间,总的空间复杂度还是O(n+k)。

稳定性:

  • 基数排序是稳定的排序算法。这意味着相等的元素在排序前后相对位置保持不变。这是因为基数排序是按位进行的,每一趟排序都是独立的,并且在收集阶段按照原顺序从桶中取出元素,从而保持了稳定性。

桶排序:

  1. 初始化桶:首先确定桶的数量和每个桶覆盖的数值范围。桶的数量和分布取决于待排序数据的特性,通常需要预先知道数据的大致分布情况。

  2. 分配元素到桶:遍历待排序数组,根据元素的值将它们分配到对应的桶中。分配的依据可以是元素的大小,例如,如果数据范围是0到100,可以创建10个桶,每个桶负责10个数的范围。

  3. 桶内排序:对每个非空的桶内部进行排序。可以选择插入排序、快速排序等算法,具体选择取决于桶内元素的数量和特性。

  4. 合并桶:将所有桶中的元素按照桶的顺序(通常是桶的索引)依次取出,合并到一个数组中,这样合并后的数组就是有序的。

 

代码实现: 

public static int[] bucketSort(int[] arr){

        int max = Integer.MIN_VALUE;
        int min = Integer.MAX_VALUE;
        for(int num : arr){
            max = Math.max(max,num);
            min = Math.min(min,num);
        }

        //初始化桶
        int bucketnum = (max-min)/arr.length+1;
        List<Integer>[] buckets = new ArrayList[bucketnum];
        for (int i = 0; i < bucketnum; i++) {
            buckets[i] = new ArrayList<>();
        }

        //将每个元素放入桶中
        for (int i = 0; i < arr.length; i++) {
            int index = (arr[i] - min) * (bucketnum - 1) / (max - min);
            buckets[index].add(arr[i]);
        }

        //对桶里面的每个元素进行排序,这里可以自己实现其他排序算法
        for (int i = 0; i < buckets.length; i++) {
            Collections.sort(buckets[i]);
        }

        //重新将桶中的每个元素放回到原数组中
        int index = 0;
        for (int i = 0; i < buckets.length; i++) {
            for(int j = 0;j<buckets[i].size();j++){
                arr[index] = buckets[i].get(j);
                index++;
            }
        }
        return arr;

    }

时间复杂度:

  • 最好情况:如果数据均匀分布在各个桶中,且桶内排序所用的算法具有良好的时间复杂度(如插入排序在小数组上接近O(n)),桶排序的整体时间复杂度可以达到O(n + k),其中n是待排序元素的数量,k是桶的数量。
  • 平均情况:同样,如果数据分布较为均匀,桶排序的时间复杂度也是O(n + k)。
  • 最坏情况:如果所有数据都集中在少数几个桶中,特别是全部集中在同一个桶里,此时桶排序的时间复杂度退化,需要对这些桶内的元素进行排序,可能会达到O(n^2),这取决于桶内排序算法的时间复杂度。

空间复杂度:

  • 桶排序的空间复杂度主要取决于桶的数量和每个桶可能存储的元素数量。最坏情况下,如果每个元素都分配到了不同的桶中,空间复杂度为O(n)加上每个桶的额外开销。通常,空间复杂度为O(n + k),其中k是桶的数量,n是数组的长度。如果桶的数量k与n成正比或者接近n,那么空间复杂度接近O(n)。

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

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

相关文章

[贪心] 区间选点问题

905. 区间选点 - AcWing题库 思路&#xff1a;就是将所有区间按照右端点排序&#xff0c; 然后选取一些区间的右端点 代码&#xff1a; #include <iostream> #include <algorithm> #include <vector> using namespace std; const int N 100010;typedef p…

Flask与HTTP

一、请求响应循环 “请求-响应循环”&#xff1a;客户端发出请求&#xff0c;服务器处理请求并返回响应。 Flask Web程序的工作流程&#xff1a; 当用户访问一个URL&#xff0c;浏览器便生成对应的HTTP请求&#xff0c;经由互联网发送到对应的Web服务器。Web服务器接收请求&a…

信号,信号列表,信号产生方式,信号处理方式

什么是信号 信号在我们的生活中非常常见&#xff1b;如红绿灯&#xff0c;下课铃&#xff0c;游戏团战信号&#xff0c;这些都是信号&#xff1b;信号用来提示接收信号者行动&#xff0c;但接收信号的人接收到信号会进行一系列的行为&#xff0c;完成某个动作&#xff1b;这就…

基于Java EE平台项目管理系统的设计与实现(论文 + 源码)

【免费】基于javaEE平台的项目管理系统.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89267688 基于Java EE平台项目管理系统的设计与实现 摘 要 随着社会信息化的发展&#xff0c;很多的社会管理问题也一并出现了根本性变化&#xff0c;项目公司的报表及文…

【YOLO】目标检测 YOLO框架之train.py参数含义及配置总结手册(全)

1.一直以来想写下基于YOLO开源框架的系列文章&#xff0c;该框架也是日常项目开发中常用的一款工具&#xff0c;最近刚好挤时间梳理、总结下这块儿的知识体系。 2.熟悉、梳理、总结下YOLO目标检测相关知识体系&#xff0c;之前实战配置时总是临时性检索些注释含义&#xff0c;但…

JVM组成之类加载器

类加载器&#xff08;ClassLoader&#xff09;&#xff1a;是Java虚拟机提供给应用程序去实现获取类和接口字节码数据的技术。 类加载器多数是有Java编写的&#xff0c;也有部分是c编写的&#xff0c;负责接收来自外部的二进制数据&#xff0c;然后执行JNI&#xff08;也就是本…

【Java】山外有山,类外还有类

【Java】山外有山&#xff0c;类外还有类 内部类是Java语言中的一种特性&#xff0c;它允许在另一个类中定义一个类。 内部类可以是静态的&#xff08;不依赖于外部类的实例&#xff09;&#xff0c;也可以是非静态的&#xff08;依赖于外部类的实例&#xff09;。 在本篇博…

在R的 RGui中,使用devtools 安装trajeR

创建于&#xff1a;2024.5.5 文章目录 1. 报错信息2. 尝试使用指定的清华镜像&#xff0c;没有解决3. 找到原因&#xff1a;官网把包删除了4. 尝试从网上下载&#xff0c;然后安装。没有成功5. 使用devtools安装5.1 尝试直接安装&#xff1a;install.packages("devtools&q…

【智能算法应用】混合粒子群算法求解CVRP问题

目录 1.算法原理2.数学模型3.结果展示4.参考文献5.代码获取 1.算法原理 【智能算法】粒子群算法&#xff08;PSO&#xff09;原理及实现 经典PSO算法用于连续空间优化问题&#xff0c;VRP问题为离散组合优化问题&#xff0c;涉及如何有效地分配一组车辆去访问多个客户点&…

OSEK的设计哲学与架构

1 前言 OSEK是为单核分布式嵌入式控制单元量身定制的实时系统&#xff0c;对事件驱动&#xff08;event driven&#xff09;的硬实时控制系统具有良好的适配性。OSEK没有强求不同软件模块间的完全兼容性&#xff0c;而是将重心放到了软件的可移植性上来。简单来说&#xff0c;与…

[报错解决]Communications link failure

报错 主机IDEA项目连接虚拟机的数据库报错。 主要报错信息有&#xff1a; com.mysql.cj.jdbc.exceptions.CommunicationsException: Communications link failure The last packet sent successfully to the server was 0 milliseconds ago. The driver has not received a…

智慧旅游引领未来风尚,科技助力旅行更精彩:科技的力量推动旅游业创新发展,为旅行者带来更加便捷、高效和智能的旅行服务

目录 一、引言 二、智慧旅游的概念与特点 &#xff08;一&#xff09;智慧旅游的概念 &#xff08;二&#xff09;智慧旅游的特点 三、科技推动旅游业创新发展 &#xff08;一&#xff09;大数据技术的应用 &#xff08;二&#xff09;人工智能技术的应用 &#xff08;…

Linux Ubuntu 开机自启动浏览器

终端输入命令&#xff1a;gnome-session-properties 打开启动设置 如果提示&#xff1a;Command ‘gnome-session-properties’ not found, but can be installed with: apt install gnome-startup-applications 则执行&#xff1a;apt install gnome-startup-applications安装…

一、写给Android开发者之harmony入门

一、创建新项目 对比 android-studio&#xff1a;ability类似安卓activity ability分为两种类型(Stage模型) UIAbility和Extensionability&#xff08;提供系统服务和后台任务&#xff09; 启动模式 1、 singleton启动模式&#xff1a;单例 2、 multiton启动模式&#xff1…

数据结构十:哈希表

本次将从概念上理解什么是哈希表&#xff0c;理论知识较多&#xff0c;满满干货&#xff0c;这也是面试笔试的一个重点区域。 目录 一、什么是哈希表 1.0 为什么会有哈希表&#xff1f; 1.1 哈希表的基本概念 1.2 基本思想 1.3 举例理解 1.4 存在的问题 1.5 总结 二、…

libcity笔记:参数设置与参数优先级

1 参数优先级 高优先级的参数会覆盖低优先级的同名参数 Libcity中的优先级顺序维&#xff1a; 命令行参数&#xff08;命令行python run_model.py时导入的&#xff09; > 用户定义配置文件&#xff08;命令行python run_model.py时由config_file导入的&#xff09; >…

javascript 练习 写一个简单 另类录入 电脑组装报价表 可打印

数据格式 &#xff08;1代表cpu、2代表主板、3代表内存、。。。&#xff09; 1i3 12100 630 2H610 480 3DDR4 3200 16G 220 4500G M.2 299 5300W电源 150 6小机箱 85 7GT 730G 4G 350 8WD 2T 399 9飞利浦 24Led 580 主代码 Html JS <!DOCTYPE html> <html lang&qu…

02_Java综述

目录 面向对象编程两种范式抽象OOP 三原则封装继承多态多态、封装与继承协同工作 面向对象编程 面向对象编程(Object-Oriented Programming&#xff0c;OOP)在Java中核心地位。几乎所有的Java程序至少在某种程度上都是面向对象的。OOP与java是密不可分的。下面说一下OOP的理论…

SSM+Vue酒店管理系统

SSMVue酒店管理系统&#xff0c;JavaWeb酒店管理系统&#xff0c;项目由maven工具管理依赖&#xff0c;数据库Mysql&#xff0c;一共19张表&#xff0c;前端用Vue写的管理端&#xff0c;功能丰富&#xff0c;需要可在最后位置联系我&#xff0c;可加购调试&#xff0c;讲解&…

自注意力架构大成者_Transformer(Pytorch 17)

1 模型简介 在上节比较了 卷积神经网络&#xff08;CNN&#xff09;、循环神经网络&#xff08;RNN&#xff09;和 自注意力&#xff08;self‐attention&#xff09;。值得注意的是&#xff0c; 自注意力同时具有并行计算和最短的最大路径长度这两个优势。因此&#xff0c;使…
最新文章