数据结构之排序补充

1. 非比较排序

上一篇文章我们罗列了数据结构中排序的八种方法。这八种方法都是需要比较才能实现的,那怎么样才可以通过非比较的方法来实现数组的排序呢?这里就提供一种非比较排序的方法。

具体的操作思路如下:

1. 先统计待比较数组arr中重复数组的个数,并相对应的记录下来。

2. 在另一个第二个新开辟的数组count里,将arr数组中的元素当作下标,将对应元素出现的个数作为元素对应放。

3. 然后遍历count数组里面的元素,如果元素不为零,就将这个数据的下标作为元素返回给原数组arr,将这个数据的元素作为返回次数继续返回。

4. 原数组arr此时就有序了。

 我们可以根据上面的思路看一下下面这个例子:

上面的数组为arr,下面的数组为count,先看arr数组中,6出现1次,1出现2次,2出现2次,9出现1次,4出现3次。所以在count数组中,下标为6的位置为1,下标为1的位置为2,下标为2的位置为2,下标为9的位置为1,下标为4的位置3。

 然后遍历count数组,下标为0没有元素,跳过,下标为1有2,那么就在arr数组中从下标为0开始,连续放两个1,然后继续遍历count数组,连续放两个2,三个4,1个6,1个9。就得到了新的arr数组1 1 2 2 4 4 4 6 9。

这种方法需要新开辟一个数组用于暂时存放数组,而这个新开辟的count数组大小与原arr数组中的最大元素是息息相关的。现在我们试着排下面这个数组:

由第一个例子我们不难知道,开辟count数组的空间就需要109+1=110(看上面的例子,要以元素中的最大值作为下标,就需要比最大值还要多一个空间大小,因为还有下标为0的位置)个整形大小的空间。而这个数组中最小值为100,意思是在tmp数组中,只有在下标为100的时候才会有元素出现,这样子的话前面99个整形大小的空间就被浪费了。并且如果数组里面的元素有负数的话,又不可能将这个负数的个数放在下标为负数的空间里。而我们利用计算机排序的数组中,这两种情况更多。所以我们可以采用下面这种优化的方法。

1. 同上,先将arr数组中的元素以及元素重复的个数对应的存储下来。数组的最大值为max,最小值为min。

2. 开辟max-min+1个空间作为count数组的空间大小。现在开辟的空间里面的值都是随机的,我们通过memset函数将空间里面的整型都初始化为0。

3. 假设arr数组中下标为i的arr[i]元素重复了n次,那么就在count数组中下标为arr[i]-min的位置定为n。

4. 当arr数组的情况全部放入count数组的后,遍历count数组,将count数组中元素不为零的下标为j的数据作为放回去的次数,值为i+min,从arr[0]开始依次放回去。

5. 此时arr数组的元素全部有序。

 现在我们继续以上面的示例数组{100,101,109,105,101,105}为例详细讲解一下这个过程:

首先原数组依然命名为arr,新开辟的数组为count。arr数组中最大值为109,最小值为100。所以开辟的count数组的大小为109-100+1=10个整型空间大小。100出现的次数为1次,101出现的次数为2次,109出现的个数为1次,105出现的个数为2次。所以在count数组中,下标为100-100=0的位置的数据为1,下标为101-100=1的位置的数据为2,下标为109-100=9的位置的数据为1,下标为105-100=5的位置的数据为2

然后遍历count数组,若数组元素为0的话直接跳过,若不为0,则将下标为j的元素count[j]作为上传次数,将j+min作为上传的数据,从arr[0]开始依次按顺序上传上去。连续放count[j]个大小为j+min的数据。最后就得到有序的数组arr{100,101,101,105,105,109}.

 通过这个过程,我们可以写一下代码:

//非比较排序
void CountSort(int* arr, int n)
{//先找数组arr中最大值max和最小值min,这里还是需要用到比较int min = arr[0];int max = arr[0];for (int i = 0; i < n; i++){if (arr[i] > max){max = arr[i];}if (arr[i] < min){min = arr[i];}}//开辟range个整型空间大小的数组countint range = max - min + 1;int* count = (int*)malloc(sizeof(int) * range);if (count == NULL){perror("malloc fail!");exit(1);}//将count数组里面的元素都初始化为0memset(count, 0, sizeof(int) * range);//将arr中下标为i的元素arr[j]-min作为下标传给count,将arr中元素出现的次数作为对应数值传给countfor (int i = 0; i < n; i++){count[arr[i] - min]++;}//将count中的下标j加上min作为数值传给arr,将count[j]作为连续的上传次数int index = 0;for (int j = 0; j < range; j++){while (count[j]--){arr[index++] = j + min;}}
}

 我们可以根据下面这个代码测试一下排序算法所需要的时间:

void test()
{srand((unsigned int)time(0));const int N = 100000;int* a1 = (int*)malloc(sizeof(int) * N);int* a2 = (int*)malloc(sizeof(int) * N);int* a3 = (int*)malloc(sizeof(int) * N);int* a4 = (int*)malloc(sizeof(int) * N);int* a5 = (int*)malloc(sizeof(int) * N);int* a6 = (int*)malloc(sizeof(int) * N);int* a7 = (int*)malloc(sizeof(int) * N);int* a8 = (int*)malloc(sizeof(int) * N);for (int i = 0; i < N; i++){a1[i] = rand();a2[i] =a1[i];a3[i] = a1[i];a4[i] = a1[i];a5[i] = a1[i];a6[i] = a1[i];a7[i] = a1[i];a8[i] = a1[i];}//测试冒泡排序int begin1 = clock();BubbleSort(a1, N);int end1 = clock();//测试直接插入排序int begin2 = clock();InsertSort(a2, N);int end2 = clock();//测试希尔排序int begin3 = clock();ShellSort(a3, N);int end3 = clock();//测试直接选择排序2int begin4 = clock();SelectSort2(a4, N);int end4 = clock();//测试快排hoare版本int begin5 = clock();QuickSort(a5, 0, N - 1);int end5 = clock();//测试非递归版本int begin6 = clock();QuickSortNonR(a6, 0, N - 1);int end6 = clock();//测试归并排序int begin7 = clock();MergeSort(a7, N);int end7 = clock();//测试非比较排序int begin8 = clock();CountSort(a8, N);int end8 = clock();printf("BubbleSort:%d\n", end1 - begin1);printf("InsertSort:%d\n", end2 - begin2);printf("ShellSort:%d\n", end3 - begin3);printf("SelectSort2:%d\n", end4 - begin4);printf("QuickSort:%d\n", end5 - begin5);printf("QuickSortNonR:%d\n", end6 - begin6);printf("MergeSort:%d\n", end7 - begin7);printf("CountSort:%d\n", end8 - begin8);free(a1);free(a2);free(a3);free(a4);free(a5);free(a6);free(a7);free(a8);}

 代码的结果如下:

我们可以看到,冒泡排序的效率最低,快排第二,而非比较排序效率第一。所以说非比较排序在某些时候使用起来效率是最高的。但是有些时候不能使用非比较排序:

1. 很多数据不集中的时候不能使用非比较排序。

2.非比较排序不能排小数。

 2. 排序算法复杂度及稳定性分析

稳定性就是两个相同的数据在排序完成前和排序完成后的相对位置不改变的话就稳定,如果改变的话就不稳定。

 不稳定的四种情况可以通过下面四种情况进行实验即可得出结论:

直接选择排序:5 8 5 2 9 

希尔排序:5 8 2 5 9

堆排序:2 2 2 2

快速排序:5 3 3 4 3 8 9 10 11

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

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

相关文章

1.62亿元!812个项目立项!上海市2024年度“科技创新行动计划”自然科学基金项目立项

本期精选SCI&EI ●IEEE 1区TOP 计算机类&#xff08;含CCF&#xff09;&#xff1b; ●EI快刊&#xff1a;最快1周录用&#xff01; 知网(CNKI)、谷歌学术期刊 ●7天录用-检索&#xff08;100%录用&#xff09;&#xff0c;1周上线&#xff1b; 免费稿件评估 免费匹配期…

危!这些高危端口再不知道问题就大了

号主&#xff1a;老杨丨11年资深网络工程师&#xff0c;更多网工提升干货&#xff0c;请关注公众号&#xff1a;网络工程师俱乐部 下午好&#xff0c;我的网工朋友。 端口作为网络通信的基本单元&#xff0c;用于标识网络服务和应用程序。 但某些端口由于其开放性和易受攻击的…

Excel中截取中文地址转换为省、市、区

使用方法/步骤 首先我们在网页打上方方格子&#xff0c;进入官网&#xff0c;下载方方格子。 解压后进行安装&#xff0c;打开OFFIE中的EXCEL&#xff0c;可以发现新新添加一个DIY工具箱&#xff0c;其中的提取地址功能可以将字符串地址解析为省、市、区 如下图所示

引入 axios,根据 api 文档生成调用接口

起步 | Axios Docs 安装 axios npm install axios 生成 api 调用接口【可选】 https://github.com/ferdikoomen/openapi-typescript-codegen 安装 npm install openapi-typescript-codegen --save-dev 然后执行生成代码 # http://localhost:8805/api/user/v3/api-docs&a…

2款使用.NET开发的数据库系统

今天大姚给大家分享2款使用.NET开发且开源的数据库系统。 Garnet Garnet是一款由微软研究院基于.NET开源的高性能、跨平台的分布式缓存存储数据库&#xff0c;该项目提供强大的性能&#xff08;吞吐量和延迟&#xff09;、可扩展性、存储、恢复、集群分片、密钥迁移和复制功能…

ARM-8 定位发布版本 pstree 程序的 main 地址

逆向时如何找到main&#xff0c;如下&#xff1a; 1.readelf -h pstree ELF Header: Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 Class: ELF64 Data: 2s complement, little endian Versi…

13.UE5流星火雨,引导施法技能制作

2-15 流星火雨&#xff0c;引导施法技能制作、随机数_哔哩哔哩_bilibili 目录 1.为流星火雨添加按键映射 2.创建流星火雨的动画蒙太奇 3.实现播放动画蒙太奇的逻辑 ​编辑 4.定义发射一波流星火雨的发射物 5.使用动画通知释放流星火雨 1.为流星火雨添加按键映射 创建名为流…

Web大型网站的性能测试要求和工具方法

Web大型网站的性能测试要求和工具方法涉及多个层面的考量&#xff0c;旨在确保网站在高并发访问、大数据量处理、复杂交互场景下仍能保持良好的用户体验和系统稳定性。以下是针对大型网站性能测试的主要要求和相应的工具与方法&#xff1a; 性能测试要求 1. 高并发处理能力&…

贪心算法day3(最长递增序列问题)

目录 1.最长递增三元子序列 2.最长连续递增序列 1.最长递增三元子序列 题目链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a;我们只需要设置两个数进行比较就好。设a为nums[0]&#xff0c;b 为一个无穷大的数&#xff0c;只要有比a小的数字就赋值…

在CentOS7传统部署wordpress

1 环境准备 所需环境说明CentOS7.9ip地址&#xff1a;10.0.0.7&#xff0c;可以上网PHP72系列软件下面会介绍MySQL数据库暴露端口3306&#xff0c;用户wordpress&#xff0c;库wordpressnginx版本任意wordpres v6.5.2代码下载地址&#xff1a;https://cn.wordpress.org/wordpr…

文献阅读 | Nature Methods:使用 STAMP 对空间转录组进行可解释的空间感知降维

文献介绍 文献题目&#xff1a; 使用 STAMP 对空间转录组进行可解释的空间感知降维 研究团队&#xff1a; 陈金妙&#xff08;新加坡科学技术研究局&#xff09; 发表时间&#xff1a; 2024-10-15 发表期刊&#xff1a; Nature Methods 影响因子&#xff1a; 36.1&#xff0…

vs2022搭建opencv开发环境

1 下载OpenCV库 https://opencv.org/ 下载对应版本然后进行安装 将bin目录添加到系统环境变量opencv\build\x64\vc16\bin 复制该路径 打开高级设置添加环境变量 vs2022新建一个空项目 修改属性添加头文件路径和库路径 修改链接器&#xff0c;将OpenCV中lib库里的o…

GA/T1400视图库平台EasyCVR多品牌摄像机视频平台前端监控摄像头镜头的基础知识

在现代安全监控系统中&#xff0c;摄像机镜头作为捕捉图像的关键组件&#xff0c;其选择和应用直接影响到监控图像的质量和系统的整体性能。随着技术的发展&#xff0c;摄像机镜头的种类和功能也在不断扩展&#xff0c;以适应各种复杂的监控环境和需求。对于相机成像来讲&#…

省级数字经济发展水平数据(2011-2022年)

数字经济是指以数据资源为关键要素&#xff0c;以现代信息网络为主要载体&#xff0c;以信息通信技术融合应用、全要素数字化转型为重要推动力&#xff0c;促进公平与效率更加统一的新经济形态。 2011-2022年省级数字经济发展水平数据&#xff08;&#xff09;.zip资源-CSDN文…

【WRF模拟】全过程总结:WPS预处理及WRF运行

【WRF模拟】全过程总结:WPS预处理及WRF运行 1 数据准备1.1 嵌套域设置(Customize domain)-基于QGis中gis4wrf插件1.2 静态地理数据1.2.1 叶面积指数LAI和植被覆盖度Fpar(月尺度)1.2.2 地面反照率(月尺度)1.2.3 土地利用类型+不透水面积1.2.4 数据处理:geotiff→tiff(W…

银行家算法(模拟)

银行家算法是一种避免死锁的有效算法&#xff0c;它借鉴了银行家贷款的策略。在分配资源之前&#xff0c;银行家会检查系统是否有足够的资源满足进程的最大需求&#xff0c;若有&#xff0c;则暂时分配资源&#xff0c;然后继续检查剩余资源是否足够满足其他进程的最大需求。只…

「QT」几何数据类 之 QSizeF 浮点型尺寸类

✨博客主页何曾参静谧的博客&#x1f4cc;文章专栏「QT」QT5程序设计&#x1f4da;全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…

【动手学电机驱动】STM32-FOC(3)STM32 三路互补 PWM 输出

STM32-FOC&#xff08;1&#xff09;STM32 电机控制的软件开发环境 STM32-FOC&#xff08;2&#xff09;STM32 导入和创建项目 STM32-FOC&#xff08;3&#xff09;STM32 三路互补 PWM 输出 STM32-FOC&#xff08;4&#xff09;IHM03 电机控制套件介绍 STM32-FOC&#xff08;5&…

Spark中的shuffle

Shuffle的本质基于磁盘划分来解决分布式大数据量的全局分组、全局排序、重新分区【增大】的问题。 1、Spark的Shuffle设计 Spark Shuffle过程也叫作宽依赖过程&#xff0c;Spark不完全依赖于内存计算&#xff0c;面临以上问题时&#xff0c;也需要Shuffle过程。 2、Spark中哪…

ffmpeg 视频滤镜:屏蔽边框杂色- fillborders

滤镜描述 fillborders 官网链接 > FFmpeg Filters Documentation fillborders滤镜有几种方式帮你屏蔽边框的杂色、不好的图案。 滤镜使用 参数 left <int> ..FV.....T. set the left fill border (from 0 to INT_MAX) (default 0)right …