数据结构之排序补充

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;用于标识网络服务和应用程序。 但某些端口由于其开放性和易受攻击的…

C/C++|关于“子线程在堆中创建了资源但在资源未释放的情况下异常退出或挂掉”如何避免?

文章目录 主线程监控子线程状态并负责清理资源使用智能指针&#xff08;RAII模式&#xff09;线程清理处理函数(pthread_cleanup_push、pthread_cleanup_pop)使用资源管理器或资源吃集中管理资源通过信号或全局变量监控线程状态使主线程负责分配和释放资源 在 C/C 中处理子线程…

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

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

OpenSIPS 转发 JSSIP 注册消息到 FreeSWITCH

OpenSIPS IP 地址&#xff1a;192.168.31.213 FreeSWITCH IP 地址&#xff1a; 192.168.31.166 转发注册消息的路由代码应该是&#xff1a; if (is_method("REGISTER")) {save("location", "r");if ($pr "ws" || $pr "wss&q…

人民法院报:环境侵权诉讼中“虚假鉴定意见”提供者的刑事责任

2023年8月&#xff0c;最高人民法院发布了《关于审理生态环境侵权责任纠纷案件适用法律若干问题的解释》和《关于生态环境侵权民事诉讼证据的若干规定》&#xff08;以下简称《规定》&#xff09;&#xff0c;旨在进一步健全完善生态环境审判法律适用规则体系&#xff0c;推动生…

React.lazy() 懒加载

概要 React.lazy() 是 React 16.6 引入的一个功能&#xff0c;用于实现代码分割&#xff08;code splitting&#xff09;。它允许你懒加载组件&#xff0c;即在需要时才加载组件&#xff0c;而不是在应用初始加载时就加载所有组件。这种方法可以显著提高应用的性能&#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…

Swift 扩展

Swift 扩展 Swift 是一种强大的编程语言&#xff0c;由苹果公司开发&#xff0c;用于iOS、macOS、watchOS和tvOS应用程序的开发。自2014年发布以来&#xff0c;Swift因其易于阅读和编写的语法、现代化的设计以及出色的性能而广受欢迎。本文将探讨Swift的一些关键特性&#xff…

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.为流星火雨添加按键映射 创建名为流…

Zabbix5 通过 Rsyslog 实现设备日志收集分析syslog及监控告警

一、概述 本文档详细描述了如何使用 Zabbix5 和 Rsyslog 实现对设备日志的收集、监控以及在满足特定条件下触发告警的完整流程&#xff0c;包括环境准备、Rsyslog 配置、Zabbix5 配置以及常见问题排查等内容。 二、环境准备 服务器环境 操作系统&#xff1a;CentOS&#xff08;…

开源竞争-利用kimi编程助手搭建小程序(11)

开源竞争&#xff1a; 当你无法彻底掌握技术的时候&#xff0c;你就开源这个技术&#xff0c;让更多的人了解这个技术&#xff0c;培养出更多的技术依赖&#xff0c;你会说&#xff0c;这不就是在砸罐子吗&#xff1f;一个行业里面总会有人砸罐子的&#xff0c;不是你先砸罐子&…

mybatis连接PGSQL中对于json和jsonb的处理

pgsql数据库表字段设置了jsonb格式&#xff1b;在java的实体里使用String或者对象转换会一直提示一个错误&#xff1a; Caused by: org.postgresql.util.PSQLException: ERROR: column "xx" is of type jsonb but expression is of type character varying 需要加一…

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

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

Java 处理 json 格式数据解析为 csv 格式

Java处理json格式数据解析为csv格式 如果不使用 JSON 工具库&#xff0c;你可以手动解析 JSON 格式字符串并将其转换为 CSV 格式字符串。 以下是一个简单示例&#xff0c;展示如何实现这一功能。 示例代码 下面的示例代码手动处理 JSON 字符串&#xff0c;将其转换为 CSV 格式字…

python+智谱AI-实现钉钉消息自动回复

python智谱AI-实现钉钉消息自动回复 实现了电脑窗口切换&#xff0c;截图识别未读消息&#xff0c;与语言模型交互后&#xff0c;将答案带入到钉钉窗口中。偷个懒&#xff0c;直接贴代码了&#xff0c;后续不断完善注释&#xff0c;如果遇到读不懂的地方&#xff0c;欢迎交流。…

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

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

Javascript如何获取指定网页中的内容?

这两天有一个需求&#xff0c;就是通过JS去获取网页的内容&#xff0c;当然&#xff0c;除了今天我要分享的这个方法以外&#xff0c;其实通过Ajax的Get方法也是可以实现这个功能的&#xff0c;但是Ajax就比较麻烦一些了&#xff0c;如果只是单纯的想要获取一下纯内容&#xff…