计数,桶与基数排序

 

目录

 

一. 计数排序

概念

 步骤思路如下

 实现代码如下

时间复杂度与空间复杂度

1. 时间复杂度

2. 空间复杂度

计数排序的特点

二. 桶排序

概念 

 步骤思路如下

实现代码如下 

时间复杂度与空间复杂度

1. 时间复杂度

2. 空间复杂度

桶排序的特点

 三. 基数排序

概念

步骤思路如下

实现代码如下

时间复杂度与空间复杂度

1. 时间复杂度

2. 空间复杂度

基数排序的特点


一. 计数排序

概念

计数排序是一种非比较排序算法,它的基本思想是利用数组下标的有序性,将元素作为计数数组的相应下标,并在该下标位置存储相应的元素数量,最后根据计数数组填充待排序数组

 步骤思路如下

1. 找出待排序数组中的最大值和最小值
遍历待排序数组,找出其中的最大值和最小值。

2. 创建计数数组
创建一个新的计数数组,其大小为(最大值 - 最小值 + 1)。
初始化计数数组的所有元素为0。

3. 统计元素出现的次数
再次遍历待排序数组,对于数组中的每个元素,将其值减去最小值(为了使得计数数组的下标从0开始),并将计数数组中对应下标的值加1。

4. 利用计数数组排序
从后向前遍历待排序数组(从大到小是为了保证稳定性,即相同元素在排序后保持原有顺序)。
对于每个元素,将其值减去最小值,然后利用计数数组找到其在排序后数组中的位置,并将该元素放到正确的位置上。
同时,将计数数组中对应位置的值减1,表示该位置已经被占用。

5. 完成排序

 实现代码如下
void CountSort(int* a,int n)
{int max=a[0], min=a[0];for (int i = 0; i < n; i++){if (a[i] > max){max = a[i];}if (a[i] < min){min = a[i];}}int* tmp = (int*)calloc(max - min +1, sizeof(int));//自动将值其置为0for (int i = 0; i < n; i++){tmp[a[i] - min]++;}int count = n-1;for (int i =  max - min; i >=0; i--){while (tmp[i]--) {a[count--] = i + min;}}free(tmp);tmp = NULL;
}
时间复杂度与空间复杂度
1. 时间复杂度

统计元素出现次数的时间复杂度为 O(n)。

根据计数数组进行排序的时间复杂度为 O(n)。

综上所述计数排序的时间复杂度为一般 O(n)

2. 空间复杂度

由于计数排序需要额外的空间来存储计数数组

所以计数排序的空间复杂度主要取决于计数数组的大小,即 n。因此,计数排序的空间复杂度为 O(n)

计数排序的特点

计数排序适用于待排序数组中的元素为非负整数(负数不是不能排),并且元素的取值范围不大于计算机可以表示的最大范围。
如果待排序数组中的元素是负数,或者元素的取值范围较大,计数排序可能不适用,因为它需要额外的空间来存储计数数组。
计数排序是一种稳定的排序算法,即相同元素在排序后保持原有的顺序

计数排序的时间复杂度为O(n),其中n是待排序数组的长度

二. 桶排序

概念 

桶排序是一种分配式排序算法,它将待排序的数据分到有限数量的桶子里。每个桶子再个别排序(可能使用别的排序算法或以递归方式继续使用桶排序进行排序)。当要被排序的数组内的数值是均匀分布的时候,桶排序使用线性时间(O(n))

 步骤思路如下

1.创建n个桶

2. 将待排序元素分散到各个桶中

3. 对每个桶内的元素排序(可以使用别的排序算法)

4. 读取每个桶的元素,按顺序放回原数组中

实现代码如下 
#define BUCKET_SIZE 100
#define MAX_NUM 10
void BucketSort(int arr[], int n) {if (n <= 1) {return;}int bucket[BUCKET_SIZE][MAX_NUM / BUCKET_SIZE + 1]; // 桶数组,每个桶的大小为MAX_NUM/BUCKET_SIZE+1int bucketIndex[BUCKET_SIZE] = { 0 }; // 每个桶的当前元素数量// 将元素放入对应的桶中for (int i = 0; i < n; i++) {int index = arr[i] / BUCKET_SIZE; // 计算桶的索引bucket[index][bucketIndex[index]++] = arr[i]; // 将元素放入桶中}// 对每个桶进行排序for (int i = 0; i < BUCKET_SIZE; i++) {if (bucketIndex[i] > 0) {InsertSort(bucket[i], bucketIndex[i]); // 使用插入排序对桶内元素进行排序// 将桶内元素放回原数组for (int j = 0; j < bucketIndex[i]; j++) {arr[i * (MAX_NUM / BUCKET_SIZE + 1) + j] = bucket[i][j];}}}
}
时间复杂度与空间复杂度
1. 时间复杂度

①最坏情况

若数据的分布非常不均匀,几乎所有的元素都进入一个桶中,那么桶排序时间复杂度为O(N²)

②最好情况

如果数据分布非常均匀,每个桶中元素数量大致相同,并且使用其他排序算法也达到最佳的时间复杂度,那桶排序时间复杂度为O(N)

③平均情况

平均情况下桶排序时间复杂度大概为O(N)

2. 空间复杂度

空间复杂度大概为O(N+M),其中M为桶的数量,N为开辟数组长度

桶排序的特点

适用于大量数据的排序,是一种高效的排序算法。相比于比较排序算法,桶排序不需要进行元素之间的比较,因此在某些情况下可以更快地完成排序。


是稳定的排序算法,相同元素的相对顺序不会改变。


需要额外的空间来存储桶,如果待排序元素数量较大,可能会占用较多的内存空间

适用于待排序元素分布均匀的情况。对于分布不均匀的数据,可能导致桶的数量不均衡,影响排序效率。

适用场景
例如在对年龄、成绩等具有一定范围的数据进行排序时。当待排序元素数量较大,且数据分布较为均匀时,桶排序可以提供较高的排序效率

 三. 基数排序

概念

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较,直至完成最高位比较

步骤思路如下

1. 寻找待排序数组中最大的数,并确定其是几位数

2. 创建两个数组,一个二维数组,一个一维数组,进入循环,最高位有多少循环多少次(从1开始,因为没有第0位)

3. (使两个数组元素为0)使用一维数组记录当前位的每个数出现的次数

4. 使用前缀和记录下来<=i数字的数量

5. 从后往前遍历存入数据(从大到小是为了保证稳定性,即相同元素在排序后保持原有顺序)。

6. 通过遍历给原数组赋值

7. 重复 2,3,4,5,6 操作直至结束

实现代码如下
int GetDigit(int x,int i)
{int count = x;int n = i;while (--n>0){count /= 10;}count %= 10;return count;
}
void RadixSort(int* a, int n)
{int max=a[0];for (int i = 0; i < n; i++){if (a[i] > max)max = a[i];}int digit1 = 0;while (max){max /= 10;digit1++;}int bucket[10][20];int tmp[20] = { 0 };//桶for(int i = 1;i<=digit1;i++){memset(bucket, 0, sizeof(bucket));memset(tmp, 0, sizeof(tmp));for (int j = 0; j < n; j++){int digit2 = GetDigit(a[j], i);tmp[digit2]++;}for (int j = 1; j < 10; j++)//前缀和记录桶中tmp[i]表示小于等于i的数字数量{tmp[j] += tmp[j - 1];}for (int j = n - 1; j >= 0; j--){int digit2 = GetDigit(a[j],i);bucket[digit2][tmp[digit2]--] = a[j];}int k = 0;for (int d = 0; d < 10; d++){for (int j = 0; j < 20; j++){if(bucket[d][j]!=0)a[k++] = bucket[d][j];}}}
}
时间复杂度与空间复杂度
1. 时间复杂度

要进行 i(最高位的位数) 趟排序 , 每趟排序需要将元素分派到k个桶,所以每趟排序的时间复杂度为O(n+k) 走i趟时间复杂度就为O(i(n+k))  但桶的个数通常是固定的,执行的躺数一般又较小,所以基数排序的时间复杂度趋近于O(n)

2. 空间复杂度

由于开辟了两个数组辅助,假设两个数组长度分别为N,M,所以基数排序的空间复杂度大概为O(N+M)

基数排序的特点

基数排序是一种稳定的排序算法。在排序过程中,相同元素的相对顺序保持不变。这是因为基数排序是按照数字的每一位进行排序的,而相同元素的每一位都是相同的,所以它们的相对顺序不会发生变化。

基数排序是一种非比较型排序算法,它不通过比较元素的大小来进行排序,而是通过分配和收集的方式实现排序。这使得基数排序在某些情况下比基于比较的排序算法(如快速排序、归并排序等)更加高效

基数排序特别适用于对整数进行排序,尤其是当待排序的整数范围不大,且整数位数相差不大时。在这种情况下,基数排序的效率很高,因为只需要进行有限次的分配和收集操作。

基数排序需要额外的空间来存储桶(或子数组),以便进行元素的分配和收集。如果待排序的元素数量很大,这可能会占用较多的内存空间。因此,在使用基数排序时,需要考虑内存使用情况。

基数排序的时间复杂度可以近似认为是线性的。这使得基数排序在处理大数据集时具有较高的效率。

基数排序不仅适用于数组排序,还适用于链表排序。因为链表在分配和收集元素时不需要移动元素本身,只需要改变节点的指针指向即可。这使得基数排序在链表排序中具有更高的效率


这篇就到这里啦,感谢支持

(๑′ᴗ‵๑)I Lᵒᵛᵉᵧₒᵤ❤

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

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

相关文章

Java核心API——Collection类

Collection类简介 * java集合框架 * java.util.Collection接口&#xff0c;是所有集合的顶级接口&#xff0c;规定了集合所必须的功能 * <p> * 集合与数组一样&#xff0c;可以保存一组具有相同类型元素数据结构 * 并且提供了对于元素的维护操作(方法)。 * 集合有多种不…

千万罚单,稠州商业银行屡教不改?

撰稿|芋圆 来源|贝多财经 今年&#xff0c;浙江稠州商业银行&#xff08;以下简称“稠州商行”&#xff09;似乎进入了多事之秋&#xff0c;刚刚兼并两家经营不善的村镇银行就紧接着收到大额罚单。 该行在2023年的经营业绩不算难看。据2023年年报&#xff0c;稠州商行的业绩从…

PHP 调用 1688 详情 API 接口的实战攻略

在电商领域&#xff0c;获取准确和详细的商品信息对于业务的发展至关重要。1688 作为国内知名的批发采购平台&#xff0c;其详情 API 接口为开发者提供了丰富的数据资源。本文将为您详细介绍如何使用 PHP 调用 1688 详情 API 接口。 一、前期准备 注册 1688 开放平台账号&#…

L2TP(Client-initiated模式)over IPSEC远程拨号实验

一、实验目的及拓扑 实验目的&#xff1a;通过L2TP客户端与LNS服务端建立L2TP隧道并承载在IPSEC网络上。其中L2TPoverIPsec客户端采用windows软终端模式&#xff08;Cloud3&#xff09;&#xff0c;AR1上将内网LNS&#xff08;FW1&#xff09;服务器采用NAT方式向外网进行映射…

基于深度学习的水果识别系统

1. 引言 随着计算机视觉技术的快速发展&#xff0c;基于深度学习的水果识别系统在农业、超市等场景中具有广泛的应用前景。例如&#xff0c;在农业中&#xff0c;水果识别系统可以帮助农民自动分类和计数水果&#xff0c;从而提高效率并减少人工成本&#xff1b;在超市中&…

【机器学习】使用Python的dlib库实现人脸识别技术

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 一、引言二、传统人脸识别技术1. 基于几何特征的方法2. 基于模板匹配的方法3. 基于统计学习的方法 三、深度学习在脸识别中的应用1. 卷积神经网络&#xff08;CNN&#xff09;2. FaceNet和ArcFace 四、使用Python和dlib库实…

Spring1(开发工具安装及配置 初始Spring 解耦实现 SpringIOC SpringDI Spring常见面试题)

目录 一 、开发工具安装及配置 IDEA简介 安装 配置 常⽤快捷键 部署maven 1.配置环境​编辑 2.创建一个maven项目​编辑 选择maven​编辑​编辑 二、初始Spring Spring历史由来 Spring体系结构 Spring生态系统 三、解耦实现 jdbc 三层思想​编辑 四…

leetcode_26. 删除有序数组中的重复项

leetcode_26. 删除有序数组中的重复项 leetcode链接 题目描述 给你一个 非严格递增排列 的数组 nums &#xff0c;请你** 原地** 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 一致 。然后返回 nums…

可视化剪辑,账号矩阵,视频分发,聚合私信一体化营销工具 源----代码开发部署方案

可视化剪辑&#xff1a; 为了实现可视化剪辑功能&#xff0c;可以使用流行的视频编辑软件或者开发自己的视频编辑工具。其中&#xff0c;通过设计用户友好的界面&#xff0c;用户可以简单地拖拽和放大缩小视频片段&#xff0c;剪辑出满足需求的视频。在开发过程中&#xff0c;可…

SQL进阶

目录 SQL索引 SQL索引 索引 作用帮助数据库管理系统高效获取数据的数据结构 数据处理分类 OLTP&#xff08;联机事务处理&#xff09;OLAP&#xff08;联机分析处理&#xff09;一般用于处理客户的事务和进行查询一般用于市场的数据分析&#xff08;数据量通常很大&#xff0…

JDK版本详解

Oracle JDK 和 OpenJDK 的对比 Oracle JDK版本将每三年发布一次&#xff0c;而OpenJDK版本每三个月发布一次&#xff1b;OpenJDK 是一个参考模型并且是完全开源的&#xff0c;而Oracle JDK是OpenJDK的一个实现&#xff0c;并不是完全开源的&#xff1b;Oracle JDK 比 OpenJDK …

多源字段聚合重塑算法

要求如下 [[{"oone": "评估是否聘请第三方机构","otwo": null,"othree": "test",},{"oone": "评估是否聘请第三方机构","otwo": null,"othree": "test",}],[{"oon…

python爬虫获取网易云音乐评论歌词以及歌曲地址

python爬虫获取网易云音乐评论歌词以及歌曲地址 一.寻找数据接口二.对负载分析三.寻找参数加密过程1.首先找到评论的请求包并找到发起程序2.寻找js加密的代码 四.扣取js的加密源码1.加密函数参数分析①.JSON.stringify(i0x)②bse6Y(["流泪", "强"])③bse6Y…

探索元宇宙:开启数字世界的奇妙之旅【小学生也能读懂】

元宇宙&#xff1a;数字新纪元的曙光 随着技术的飞速发展&#xff0c;我们正站在一个全新的数字时代的门槛上。元宇宙&#xff08;Metaverse&#xff09;&#xff0c;这个听起来充满未来感的词汇&#xff0c;已经成为科技界的热门话题。它不仅仅是一个概念&#xff0c;更是一个…

C语言——字符串两种声明初始化方式、输入输出及常见处理函数

C语言中的字符串是一个字符数组&#xff0c;它以空字符&#xff08;\0&#xff09;作为结束标志。这意味着字符串中的字符是连续存储在内存中的&#xff0c;而字符串的末尾会自动添加一个\0字符来表示字符串的结束。这种表示方式使得C语言在处理字符串时非常灵活&#xff0c;但…

第1关 -- Linux 基础知识

闯关任务 完成SSH连接与端口映射并运行hello_world.py ​​​​ 可选任务 1 将Linux基础命令在开发机上完成一遍 可选任务 2 使用 VSCODE 远程连接开发机并创建一个conda环境 创建新的虚拟环境lm3 可选任务 3 创建并运行test.sh文件 参考文档 文档&#xff1a;https://g…

【MySQL-19】一文带你了解存储函数

前言 大家好吖&#xff0c;欢迎来到 YY 滴MySQL系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的《Lin…

ROS2中间件

ROS2 是重新设计的 Robot Operating System&#xff0c;无论从用户API接口到底层实现都进行了改进。这里主要关注ROS2 的中间件。 1. 通信模式 ROS2 使用DDS协议进行数据传输&#xff0c;并通过抽象的rmw&#xff0c;支持多个厂家的DDS实现&#xff08;FastDDS&#xff0c;Cyc…

Python 和 R两者的主要区别和优缺点对比

有个问题&#xff0c;既然做模型调的还是python&#xff0c;那为啥很多人还用R呢&#xff1f; 这是一个很好的问题。Python 和 R 都是数据科学和统计分析领域中非常流行的编程语言&#xff0c;它们各有优缺点&#xff0c;选择哪种语言通常取决于具体的任务需求、个人或团队的技…

【链表】算法题(二) ----- 力扣/牛客

一、链表的回文结构 思路&#xff1a; 找到链表的中间节点&#xff0c;然后逆置链表的后半部分&#xff0c;再一一遍历链表的前半部分和后半部分&#xff0c;判断是是否为回文结构。 快慢指针找到链表的中间节点 slow指针指向的就是中间节点 逆置链表后半部分 逆置链表后半部分…