【C++】十大排序算法之 桶排序 基数排序

本次介绍内容参考自:十大经典排序算法(C++实现) - fengMisaka - 博客园 (cnblogs.com)

排序算法是《数据结构与算法》中最基本的算法之一。

十种常见排序算法可以分为两大类:

  • 比较类排序:通过比较来决定元素间的相对次序,时间复杂度为 O(nlogn)~O(n²)。
  • 非比较类排序:不通过比较来决定元素间的相对次序,其时间复杂度可以突破 O(nlogn),以线性时间运行。

【十大经典排序算法分类】

十大经典排序算法的复杂度分析

名词解释

  • 时间/空间复杂度:描述一个算法执行时间/占用空间与数据规模的增长关系。

  • n:待排序列的个数。

  • k:“桶”的个数(上面的三种非比较类排序都是基于“桶”的思想实现的)。

  • In-place:原地算法,指的是占用常量内存,不占用额外内存。即空间复杂度为 O(1) 。

  • Out-place:非原地算法,占用额外内存。

  • 稳定性:假设待排序列中两元素相等,排序前后这两个相等元素的相对位置不变,则认为是稳定的。



一、桶排序(Bucket-Sort)

       桶排序 (Bucket sort)是计数排序的升级版。它利用了函数的映射关系,高效与否的关键就在于这个映射函数的确定。桶排序的工作的原理:假设输入数据服从均匀分布,将数据分到有限数量的桶里,每个桶再分别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排)。

1.1、算法描述

  • 设置一个定量的数组当作空桶;
  • 遍历输入数据,并且把数据一个一个放到对应的桶里去;
  • 对每个不是空的桶进行排序;
  • 从不是空的桶里把排好序的数据拼接起来。

1.2、动图演示

桶排序动图演示


1.3、C++编码

/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file BucketSort.hpp
* @brief 桶排序
* @autor 写代码的小恐龙er
* @date 2024/03/07
*/

// 【分治法】
// 时间复杂度O(n + k)
// 空间复杂度O(n + k)



void BucketSort(int arr[], int n, int r) {
    if (arr == NULL || r < 1) return;

    // 根据最大/最小元素和桶数量,计算出每个桶对应的元素范围
    int max = arr[0], min = arr[0];
    int i, j;
    for (i = 1; i < n; i++) {
        if (max < arr[i]) max = arr[i];
        if (min > arr[i]) min = arr[i];
    }
    // 防止数据溢出 将桶个数加1[如: max - min + 1 = 10;  r = 3; 则需要四个桶]
    int range = (max - min + 1) / r++;

    // 建立桶对应的二维数组,一个桶里最多可能出现 n 个元素
    vector<vector<int>> buckets(r, vector<int>(n, 0));
    vector<int> counts(n, 0);

    for (i = 0; i < n; i++) {
        int k = (arr[i] - min) / range;
        buckets[k][counts[k]++] = arr[i];
    }

    int index = 0;
    for (i = 0; i < r; i++) {
        // 分别对每个非空桶内数据进行排序,比如计数排序
        if (counts[i] == 0) continue;
        sort(buckets[i].begin(), buckets[i].begin() + counts[i]);
        //counting_sort(buckets[i], counts[i]);
        // 拼接非空的桶内数据,得到最终的结果
        for (j = 0; j < counts[i]; j++) {
            arr[index++] = buckets[i][j];
        }
    }
}

1.4 、算法分析

       桶排序是稳定排序,但仅限于桶排序本身,假如桶内排序采用了快速排序之类的非稳定排序,那么就是不稳定的。



二、基数排序(Radix Sort)

        基数排序(Radix Sort)是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次类推,直到最高位。有时候有些属性是有优先级顺序的,先按低优先级排序,再按高优先级排序。最后的次序就是高优先级高的在前,高优先级相同的低优先级高的在前。

2.1 、算法描述

  • 取得数组中的最大数,并取得位数;
  • arr 为原始数组,从最低位开始取每个位组成 radix 数组;
  • 对 radix 进行计数排序(利用计数排序适用于小范围数的特点)。

2.2 、动图演示

基数排序动图演示


2.3、C++编码

/**
* @version Copyright (c) 2024 NCDC, Servo。 Unpublished - All rights reserved
* @file RadixSort.hpp
* @brief 基数排序
* @autor 写代码的小恐龙er
* @date 2024/03/07
*/

// 【分治法】
// 时间复杂度O(n * k)
// 空间复杂度O(n + k)

// 基数,范围0~9
#define RADIX 10

void RadixSort(int arr[], int n) {
    // 获取最大值和最小值
    int max = arr[0], min = arr[0];
    int i, j, l;
    for (i = 1; i < n; i++) {
        if (max < arr[i]) max = arr[i];
        if (min > arr[i]) min = arr[i];
    }
    // 假如序列中有负数,所有数加上一个常数,使序列中所有值变成正数
    if (min < 0) {
        for (i = 0; i < n; i++) arr[i] -= min;
        max -= min;
    }
    // 获取最大值位数
    int d = 0;
    while (max > 0) {
        max /= RADIX;
        d ++;
    }
    vector<vector<int>> queue(RADIX, vector<int>(n, 0);

    int count[RADIX] = {0};
    for (i = 0; i < d; i++) {
        // 分配数据
        for (j = 0; j < n; j++) {
            // 依次从个位到最高位取出数值
            int key = arr[j] % (int)pow(RADIX, i + 1) / (int)pow(RADIX, i);
            // 放置到对应位数的数组中, 同时 count[key]++ 是为了 记录 位数相同的值 的个数
            queue[key][count[key]++] = arr[j];
        }
        // 收集数据
        int c = 0;
        // 依次将各个基数数组中的值排列起来 
        for (j = 0; j < RADIX; j++) {
            for (l = 0; l < count[j]; l++) {
                arr[c++] = queue[j][l];
                queue[j][l] = 0;
            }
            count[j] = 0;
        }
    }
    // 假如序列中有负数,收集排序结果时再减去前面加上的常数
    if (min < 0) {
        for (i = 0; i < n; i++) arr[i] += min;
    }
}

2.4 、算法分析

        基数排序是稳定排序,适用于关键字取值范围固定的排序。


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

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

相关文章

吴恩达deeplearning.ai:机器学习项目的完整周期伦理

以下内容有任何不理解可以翻看我之前的博客哦&#xff1a;吴恩达deeplearning.ai专栏 文章目录 语音识别部署公平、偏见、伦理 这节博客中&#xff0c;我们主要看看构建一个机器学习的完整周期是什么&#xff0c;也就是说&#xff0c;当你想构建一个有价值的机器学习系统时&am…

vsphere虚拟机迁移是灰色如何解决

vsphere虚拟机迁移是灰色如何解决 问题描述&#xff1a; 在vsphere中&#xff0c;迁移虚拟机时迁移按钮是灰色&#xff0c;无法迁移&#xff0c;关机之后也无法迁移 虚拟机按钮为灰色 找到虚拟机存储对应的位置&#xff0c;查询是否有.vmx虚拟机文件 查询中发现有.vmx文件存…

史上最全的大数据开发八股文【自己的吐血总结】

自我介绍 我本硕都是双非计算机专业&#xff0c;从研一下开始学习大数据开发的相关知识&#xff0c;从找实习到秋招&#xff0c;我投递过100公司&#xff0c;拿到过10的offer&#xff0c;包括滴滴、字节、蚂蚁、携程、蔚来、去哪儿等大厂&#xff08;岗位都是大数据开发&#…

System Verilog学习笔记(十八)——线程控制

线程控制 发生器把激励传给代理时&#xff0c;环境类需要知道发生器什么时候完成任务&#xff0c;以便及时终止测试平台中还在运行的线程&#xff0c;这个过程就需要借助线程间的通信来完成。常用的线程间通信有事件控制、wait语句、SV信箱和旗语等。 Verilog对语句有两种分组…

Lego-loam 算法三维建图

运行环境 Linux&#xff1a;Ubuntu18.04ros&#xff1a;MelodicCeres Solver 2.0.0&#xff08;Ubuntu18.04安装Ceres&#xff09;PCL 1.8.1&#xff08;Ubuntu系统的PCL、Eigen卸载和安装&#xff09; 运行数据集 lego-loam 39/39 终端一&#xff1a;进入catkin_ws工作空间…

线程池不香了? 结构化并发才是王道!

我们先定义获取用户信息任务&#xff1a; 再定义获取订单信息任务&#xff1a; 然后再构造线程池并执行任务&#xff1a; 输出结果为&#xff1a; 看上去一切都刚刚好&#xff0c;但是&#xff0c;如果获取订单信息时出错了&#xff0c;此时会是什么现象呢&#xff1f;修改获取…

Java并发编程-实现多线程的四种方式

创建线程的四种方式 创建线程的四种方式包括使用继承 Thread 类、实现 Runnable 接口、使用 Callable 和 Future 接口以及利用线程池。每种方式都有其特定的优势和适用场景。通过继承 Thread 类或实现 Runnable 接口&#xff0c;可以定义线程要执行的任务&#xff0c;并通过调用…

计划任务和日志

一、计划任务 计划任务概念解析 在Linux操作系统中&#xff0c;除了用户即时执行的命令操作以外&#xff0c;还可以配置在指定的时间、指定的日期执行预先计划好的系统管理任务&#xff08;如定期备份、定期采集监测数据&#xff09;。RHEL6系统中默认已安装了at、crontab软件…

javascript中的强制类型转换和自动类型转换

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; 所属专栏&#xff1a;前端泛海 景天的主页&#xff1a;景天科技苑 文章目录 1.转换函数2.强制类型转换&#xff08;1&#xff09;Number类型强转&…

【蓝桥杯】路径之谜(DFS)

一.题目描述 小明冒充 X 星球的骑士&#xff0c;进入了一个奇怪的城堡。 城堡里边什么都没有&#xff0c;只有方形石头铺成的地面。 假设城堡地面是 nn 个方格。如下图所示。 按习俗&#xff0c;骑士要从西北角走到东南角。可以横向或纵向移动&#xff0c;但不能斜着走&#x…

Linux文件描述符剖析

文章目录 文件描述符文件描述符分配规则重定向软硬链接软链接&#xff08;Symbolic Link&#xff09;&#xff1a;硬链接&#xff08;Hard Link&#xff09;&#xff1a; 文件描述符 文件描述符&#xff08;File Descriptor&#xff09;是一个非负整数&#xff0c;用于标识打开…

OJ习题之——圆括号编码

圆括号编码 1.题目描述2.完整代码3.图例演示 1.题目描述 题目描述 令Ss1 s2 …sn是一个规则的圆括号字符串。S以2种不同形式编码&#xff1a; &#xff08;1&#xff09;用一个整数序列Pp1 p2 … pn编码&#xff0c;pi代表在S中第i个右圆括号的左圆括号数量。&#xff08;记为…

C++——string(2)

5. string类非成员函数 上面的几个接口大家了解一下&#xff0c;下面的OJ题目中会有一些体现他们的使用。string类中还有一些其他的 操作&#xff0c;这里不一一列举&#xff0c;大家在需要用到时不明白了查文档即可。 试用rfind、substr、find、find_first_(not)_of void te…

WordPress供求插件API文档:用户登录

该文档为WordPress供求插件文档&#xff0c;详情请查看 WordPress供求插件&#xff1a;一款专注于同城生活信息发布的插件-CSDN博客文章浏览阅读67次。WordPress供求插件&#xff1a;sliver-urban-life 是一款专注于提供同城生活信息发布与查看的插件&#xff0c;该插件可以实…

Java中super关键字作用及解析

在 Java 中&#xff0c;super关键字主要有以下作用&#xff1a; 在子类构造方法中调用父类的构造方法&#xff1a;使用super关键字可以在子类的构造方法中显式调用父类的构造方法&#xff0c;以便继承父类的属性和行为。语法如下&#xff1a;这样可以确保父类的构造方法被正确…

Sora:AI视频生成的新机遇与挑战

随着科技的飞速进步&#xff0c;人工智能&#xff08;AI&#xff09;和机器学习&#xff08;ML&#xff09;技术已经深入渗透到社会的各个领域。其中&#xff0c;Sora这类基于AI的视频生成工具因其高度逼真的生成能力而备受瞩目。然而&#xff0c;正如一枚硬币有两面&#xff0…

Vue+Vue CLI学习

1、Vue基础 1.1、Vue简介 &#xff08;1&#xff09;Javascript框架 &#xff08;2&#xff09;简化Dom操作 &#xff08;3&#xff09;响应式数据驱动 vue基础&#xff1b;vue-cli;vue-router;vuex;element-ui;vue3 vue文件包括html、css、js 1.2、第一个Vue程序 Vue …

python异常机制

当代码出现异常后底下代码都不会被执行了&#xff0c;也就是程序崩溃了。当然能避免异常的话尽量避免但是有的时候这个是没有办法避免的。 异常处理 &#xff08;注&#xff1a;异常处理是从上往下处理&#xff0c;所以编写代码时要注意&#xff09; 语法 try:可能出现异常…

ospf虚链路实验简述

1、ospf虚链路实验简述 ospf虚链路配置 为解决普通区域不在骨干区域旁&#xff0c;通过配置Vlink-peer实现不同区域网络设备之间建立逻辑上的连接。 实验拓扑图 r1: sys sysname r1 undo info enable int loopb 0 ip add 1.1.1.1 32 ip add 200.200.200.200 32 quit int e0/0/…

(sub)三次握手四次挥手

TCP的三次握手与四次挥手理解及面试题 序列号seq&#xff1a;占4个字节&#xff0c;用来标记数据段的顺序&#xff0c;TCP把连接中发送的所有数据字节都编上一个序号&#xff0c;第一个字节的编号由本地随机产生&#xff1b;给字节编上序号后&#xff0c;就给每一个报文段指派一…