基数排序分析

news2024/11/15 0:16:37

🥔 原理介绍:

[排序算法] 基数排序 (C++) - Amαdeus - 博客园

前述的各类排序方法都是建立在关键字比较的基础上,而基数排序是一种非比较型整数排序算法。它的基本思想是将整数按位数切割成不同的数字,然后按每个位数分别比较。

例如,将数字按个位、十位、百位...分别比较,基数排序有两种方法:

  • MSD:从低位到高位进行排序。这样从最低位开始排序时,较小的数就先出现在桶里。

  • LSD:从高位到低位进行排序。这样从最高位开始排序时,较大的数就先出现在桶里。

基数排序算法适用于对多个整数或者多个字符串进行升序或降序排序。 

一个整数由多个数字组成,例如 123 由 1、2、3 这 3 个数字组成;一个字符串由多个字符组成,例如 "lisi" 由 "l"、"i"、"s"、"i" 这 4 个字符组成。基数排序算法的实现思路是:对于待排序序列中的各个元素,依次比较它们包含的各个数字或字符,根据比较结果调整各个元素的位置,最终就可以得到一个有序序列。

 详见:基数排序算法

🥔 特点:

  1. 非比较型排序算法:基数排序不通过比较来决定元素间的相对次序,而是通过对数据的每位进行计数来确定每个数字的位置。

  2. 稳定性:基数排序是稳定的排序算法,也就是说,在基数排序过程中,相同大小的数字的相对位置不会发生变化。

  3. 时间复杂度:基数排序的时间复杂度取决于数据范围和数据的位数。当数据范围很小,且数据的位数较少时,基数排序是一种较快的排序算法。

  4. 空间复杂度:基数排序需要较多的空间来存储桶和计数器,因此空间复杂度较高。

  5. 适用范围:基数排序适用于排序非负整数,并且在数据范围不大,且数据的位数较少的情况下效率较高。

🥔 代码示例:

数组数字排序:

/************************************************************
 * @description: heap sort 
 * @author: kashine
 * @version: 1.0
 * @mail: likaiqinchina@gmail.com
 * @date: 2022/12/31
*************************************************************/

#include <iostream>
using namespace std;

// 对于数字来讲0~9,MAX = 10,对于字符串来讲a~z,MAX = 26
#define MAX 10 //基数

//计数排序算法
// array:数组
// place:数位,如1 10 100 1000等
// 按照某一位对数组array进行排序
void counting_sort(int array[], int place, int size) 
{
    int output[size];
    // 初始化一个数组,记录各个元素的出现次数
    int count[MAX] = { 0 };// 统计每个桶放了几个数字

    // 统计各个元素出现的次数
    for (int i = 0; i < size; i++) count[(array[i] / place) % 10]++;

    // if(place == 1)
    // {
    //     cout<< "个位各个数字出现次数:";
    //     for(int i = 0; i < 10; i++)cout<< count[i]<< " ";
    //     cout<<endl;
    // }

    // 累加count 数组中的出现次数
    // 真的是妙!
    // 某个数字,比如2,个位数为2的可能有多个,个位数比2小的可能同样有多个
    // 那么个位数为2的元素放在哪里呢?前面肯定是个位数小于2的,个数为:个位数小于2的数字的个数和,
    // 个位数同样为2的放在其后面,顺序不限
    // 上面的count中从下标0~9,代表着各个个位数字出现次数,按照下面方式累加
    // cout[2]变为第二个元素应该放的位置,也就是2出现次数加上1、0出现次数
    // 假如存在2个 个位数为2的数字,其前面只有一个 个位数为0的数字,
    // 那么cout[0] = 1; cout[1] = 0; cout[2] = 2;
    // 经过累加之后cout[0] = 1; cout[1] = [1]; cout[2] = 3;
    // 也就是说个位数为0的应该放在第一个位置,下标-1,即下标为0的位置
    // 由于不存在个位数为1的数字,所以count[1]不会被访问,不影响前后数字存放
    // 个位数为2的数字应该放在第三个位置,下标为3 - 1 = 2
    // 由于存在两个个位数为2的数字,在存放完一个个位数为2的数字之后,将count[2] - 1,
    // 下次再遇到个位数为2的数字,存放在前一个位置,也就是下标为1的位置,再次cout[2] - 1,
    // 由于不存在第三个个位数为2的数字,所以cout[2]不会被继续访问递减,
    // count[2]最终等于个位数小于2的数字个数
    for (int i = 1; i < 10; i++) count[i] += count[i - 1];

    // if(place == 1)
    // {
    //     cout<< "从小到大累加后:";
    //     for(int i = 0; i < 10; i++)cout<< count[i]<< " ";
    //     cout<<endl;
    // }

    // 根据count 数组中的信息,找到各个元素排序后所在位置,存储在output 数组中
    for (int i = size - 1; i >= 0; i--)
    {
        output[count[(array[i] / place) % 10] - 1] = array[i];
        count[(array[i] / place) % 10]--;
    }
    // 将output 数组中的数据原封不动地拷贝到 array 数组中
    for (int i = 0; i < size; i++) array[i] = output[i];
}

// 找到整个序列中的最大值
int get_max(int array[], int size) 
{
    int i, max = array[0];
    for (i = 1; i < size; i++)
        if (array[i] > max)
            max = array[i];
    return max;
}

// 基数排序算法
void radix_sort(int array[], int size) {
    // 找到序列中的最大值
    int place, max = get_max(array, size);
    // 根据最大值具有的位数,从低位依次调用计数排序算法
    for (place = 1; max / place > 0; place *= 10)
        counting_sort(array, place, size);
}

// 输出 array 数组中的数据
void display_array(int array[], int size) {
    int i;
    for (i = 0; i < size; ++i) {
        cout<< array[i]<< " ";
    }
    cout<< endl;
}

int main() {
    int array[12] = { 121, 432, 564, 23, 1, 10, 45, 788, 2, 6, 23, 19};
    int size = sizeof(array) / sizeof(array[0]);
    display_array(array, size);// 前
    radix_sort(array, size);
    display_array(array, size);// 后

    return 0;
}

🥔 算法复杂度:

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

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

空间复杂度:O(n + k)

k为程序中place变量大小,在对数组排序的时候为10,对小写字符串排序的时候为26。

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

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

相关文章

单片机基础知识之定时计数器和寄存器

目录 一、定时计数器 二、什么是寄存器 三、定时器如何定时10毫秒 四、定时器编程前寄存器配置计划 五、编程定时器控制LED每隔一秒亮灭 一、定时计数器 1、定时计数器的概念引入 定时器和计数器&#xff0c;电路一样 定时或者计数的本质就是让单片机某个部件数数 当定…

Linux基础------高级IO

文章目录阻塞IO非阻塞IO信号驱动异步IO多路转接&#xff08;核心终点&#xff09;实际上 IO “等” 拷贝 等什么呢&#xff1f; -----> 等待的是内核将数据准备好。 拷贝-------> 数据从内核考到用户 IO话题&#xff1a; 无非就是 1 &#xff0c; 改变等的方式 2 &…

Linux中编译带kafka模块的搜狗workflow开源库

workflow依赖的第三方库 openssl https://github.com/openssl/openssl apt install libssl-dev zlib https://github.com/madler/zlib git clone https://github.com/madler/zlib.git./configuremake -j4 make install lz4 (版本>1.7.5) https://github.com/lz4/lz4 …

C语言:预处理(2)

宏通常被用于执行简单的运算。 宏相比于函数的优势&#xff1a; 1.用于调用函数和从函数返回的代码可能比实际执行这个小型计算工作所需要的时间更多。所以宏比函数在程序的规模和速度方面更胜一筹。 2.更为重要的是函数的参数必须声明为特定的类型。所以函数只能在类型合适的…

Diffusion Model原理详解及源码解析

&#x1f34a;作者简介&#xff1a;秃头小苏&#xff0c;致力于用最通俗的语言描述问题 &#x1f34a;专栏推荐&#xff1a;深度学习网络原理与实战 &#x1f34a;近期目标&#xff1a;写好专栏的每一篇文章 &#x1f34a;支持小苏&#xff1a;点赞&#x1f44d;&#x1f3fc;、…

KubeSphere中间件部署

目录 &#x1f9e1;应用部署总览 &#x1f9e1;中间件部署 MySQL有状态副本集 &#x1f360;KubeSphere创建配置集 &#x1f360;KubeSphere创建存储卷 &#x1f360;KubeSphere创建有状态副本集 &#x1f360;集群访问 &#x1f49f;这里是CS大白话专场&#xff0c;让枯…

Entity Framework Core 代码自动化迁移

简述 文章内容基于&#xff1a;.NET6 Entity Framewor kCore 7.0.* 使用 EF Core 进行 Code First 开发的时候&#xff0c;肯定会遇到将迁移更新到生产数据库这个问题&#xff0c;大多数都是使用命令生成迁移 SQL&#xff0c;然后使用 SQL 脚本将更新迁移到生产数据库的方式&a…

【一起从0开始学习人工智能0x03】文本特征抽取TfidVectorizer

文章目录文本特征抽取TfidVectorizerTfidVecorizer--------Tf-IDFTF-IDF------重要程度文本特征抽取TfidVectorizer 前几种方法的缺点&#xff1a;有很多词虽然没意义&#xff0c;但是出现次数很多&#xff0c;会影响结果&#xff0c;有失偏颇------------关键词 TfidVecoriz…

一篇文章带你搞懂nodeJs环境配置

1、nodeJs下载地址&#xff0c;这里可以选择你想要的版本&#xff0c;我这里以14.15.1为例 2、下载完成后&#xff0c;直接傻瓜式安装即可。 3、打开命令行&#xff08;以管理员身份打开&#xff09;,输入node -v&#xff0c;出现以下版本号&#xff0c;代表node成功安装 4、在…

html+css设计两个摆动的大灯笼

实现效果 新年马上就要到了&#xff0c;教大家用htmlcss设计两个大灯笼&#xff0c;喜气洋洋。 html代码&#xff1a; html代码部分非常简单&#xff0c;将一个灯笼分成几部分进行设计&#xff0c;灯笼最上方部分&#xff0c;中间的线条部分和最下方的灯笼穗。组合在一起就…

docker系列教程:docker图形化工具安装及docker系列教程总结

通过前面的学习,我们已经掌握了docker-compose容器编排及实战了。高级篇也算快完了。有没有相关,我们前面学习的时候,都是通过命令行来操作docker的,难道docker就没有图形化工具吗?答案是肯定有的。咱们本篇就来讲讲docker图形化工具及使用图形化工具安装Nginx及docker系列…

读书系列2022(下)读书纪录片

目录 一、认知类 二、纪录片 一、认知类 《蓝海战略》&#xff1a; 让你(企业/个人)在竞争中产生错位竞争&#xff0c;获得优势 《认知盈余》&#xff1a;“人们实际上很喜欢创造并分享”&#xff0c; 参与是一种行为 将人们的自由时间和特殊才能汇聚在一起&#xff0c;共同…

移动Web【字体图标、平面转换[位移,旋转,转换原点,多重转换]、渐变】

文章目录一、字体图标1.1 图标库1.2 下载字体包&#xff1a;1.3 使用字体图标&#xff1a;1.4 使用字体图标 – 类名&#xff1a;1.5 案例&#xff1a;淘宝购物车1.6 上传矢量图&#xff1a;二、平面转换2.1 位移2.1 位移-绝对定位居中2.3 案例2.4 旋转2.5 转换原点2.6 多重转换…

2022年终总结:不一样的形式,不一样的展现

Author&#xff1a;AXYZdong 硕士在读 工科男 有一点思考&#xff0c;有一点想法&#xff0c;有一点理性&#xff01; 定个小小目标&#xff0c;努力成为习惯&#xff01;在最美的年华遇见更好的自己&#xff01; CSDNAXYZdong&#xff0c;CSDN首发&#xff0c;AXYZdong原创 唯…

你真的了解表达式求值吗?

表达式求值大家很熟悉特别是整型十进制的表达式求值。那么char类型的表达式求值是怎么样的&#xff1f;Eg&#xff1a;#include <stdio.h>int main() {char a 127;char b 3;char c a b;printf("%d %d %d\n",a,b,c);return 0; }上面程序输出的结果是多少&am…

2022跟学尚硅谷Maven入门(一)纯命令行

2022跟学尚硅谷Maven入门 一 纯命令行Maven从小白到专家应用场景开发过程自动部署私有仓库课程介绍小白目标普通开发人员目标资深开发人员目标第一章:Maven 概述第一节 为什么要学习MavenMaven 作为依赖管理工具(1)jar包的规模(2)jar 包的来源(3)jar包之间的依赖关系Maven 作为…

APSIM练习:播种作物练—高粱作物模拟

在本练习中&#xff0c;您将观察作物在一个季节内的生长情况。您将更多地了解如何使用 APSIM 对施肥率进行“假设”实验。这些技能不仅可以用来试验施肥率&#xff0c;还可以用来试验变量&#xff0c;例如&#xff1a; 种植时间。播种率。作物比较和不同的起始土壤水分条件。 …

C++之异常

文章目录一、C 语言传统的处理错误的方式二、C 异常概念三、异常的使用1.异常的抛出和捕获2.异常的重新抛出3.异常安全4.异常规范四、自定义异常体系五、C 标准库的异常体系六、异常的优缺点一、C 语言传统的处理错误的方式 传统的错误处理机制&#xff1a;   ① 终止程序&a…

JUC(十)-线程池-ThreadPoolExecutor分析

ThreadPoolExecutor 应用 & 源码解析 文章目录ThreadPoolExecutor 应用 & 源码解析一、线程池相关介绍1.1 为什么有了JDK提供的现有的创建线程池的方法(Executors类中的方法),然而还需要自定义线程池ThreadPoolExecutor 提供的七个核心参数大致了解JDK提供的几种拒绝策…

一辆适合长途出行的电动跑车 奥迪RS e-tron GT正式上市

作为奥迪品牌电动化发展的先锋力作&#xff0c;奥迪RS e-tron GT不止是前瞻科技的呈现&#xff0c;在e-tron纯电技术的加持下&#xff0c;更传递着RS的情怀&#xff0c;承载着人们对GT豪华休旅生活的向往。 2022年12月30日&#xff0c;伴随着Audi Channel第九期直播节目盛大开播…