高性能排序函数实现方案

news2024/9/24 21:17:23

如C语言的qsort()、Java的Collections.sort(),这些排序函数如何实现?

1 合适的排序算法?

线性排序算法的时间复杂度较低,适用场景特殊,通用排序函数不能选择。

  • 小规模数据排序,可选时间复杂度O(n^2)算法
  • 大规模数据排序,时间复杂度O(nlogn)算法更高效

为兼顾任意规模数据的排序,一般首选时间复杂度O(nlogn)排序算法:堆排、快排都有较多应用,如JDK采用堆排实现排序函数,C使用快排。

2 归排分析

使用归排情况不多。快排最坏时间复杂度O(n^2),而归排能做到平均、最坏时间复杂度都是O(nlogn),看起来诱人,为何没被“宠信”?

归排不是原地排序算法,空间复杂度O(n)。粗略夸张点讲,待排序100MB数据,除数据本身占用内存,排序还额外再占100MB内存空间,空间耗费翻倍。

快排更适合实现排序,但快排最坏时间复杂度O(n2)。

3 优化快排

数据原来就有序或接近有序,每次分区点都选择最后一个数据,则快排就很差,时间复杂度退化为O(n2)。主要还是分区点不合理。

最理想分区点

被分区点分开的两个分区数据量差不多。为提高排序算法性能,尽可能让每次分区都平均:

3.1 三数取中法

从区间的首、尾、中,分别取个数,对比大小,取这3数中间值作为分区点。

这样每隔某固定长度,取数出来比较,将中间值作为分区点,比纯粹取某数据好。但若排序数组较大,则“三数取中”可能就不够,可能“五数取中”或“十数取中”。

3.2 随机法

每次从待排序区间,随机选一个元素作为分区点。

这不能保证每次分区点都选得好,但也不大可能每次分区点都选得差,平均情况下,这样选分区点较好。时间复杂度退化为最糟糕的 O ( n 2 ) O(n2) O(n2)情况概率不大。

快排用递归实现,而递归要避免堆栈溢出:

  • 限制递归深度
    一旦递归过深,超过设定阈值,就停止递归
  • 在堆上模拟实现一个函数调用栈
    手动模拟递归压栈、出栈的过程,这样就没有了系统栈大小的限制。

4 总结

如Glibc的qsort()函数,名字很像基于快排,实际并不仅用快排。

qsort()优先使用归排,因归排空间复杂度 O ( n ) O(n) O(n),对小数据量排序,额外所需内存空间不大,即空间换时间。

但若数据量太大,归排不合适。改为快排。qsort()如何选择快排分区点?“三数取中法”。

递归太深会导致堆栈溢出,qsort()自己实现一个堆上的栈,手动模拟递归来解决。qsort()不仅用到归排、快排,还用到插排。快排过程中,当要排序的区间中,元素个数≤4,qsort()就退化为插排,不再续用递归做快排,因为小规模数据, O ( n 2 ) O(n2) O(n2)时间复杂度算法不一定比 O ( n l o g n ) O(nlogn) O(nlogn)的算法执行时间长。

算法性能可通过时间复杂度分析,但这种复杂度分析较偏理论,实际上时间复杂度并不等于代码实际的运行时间。

时间复杂度代表的是增长趋势,画成增长曲线图,发现 O ( n 2 ) O(n2) O(n2) O ( n l o g n ) O(nlogn) O(nlogn)增长趋势更猛。大O复杂度表示法中,会省略低阶、系数和常数,即O(nlogn)在没有省略低阶、系数、常数之前可能是O(knlogn + c),而k和c有可能还是个较大的数。

假设k=1000,c=200,当我们对小规模数据(比如n=100)排序时,n2的值实际上比knlogn+c还要小。
k n l o g n + c = 1000 ∗ 100 ∗ l o g 100 + 200 > > 10000 knlogn+c = 1000 * 100 * log100 + 200 >> 10000 knlogn+c=1000100log100+200>>10000
n 2 = 100 ∗ 100 = 10000 n^2 = 100*100 = 10000 n2=100100=10000

所以,小规模数据排序, O ( n 2 ) O(n2) O(n2)排序算法不一定比 O ( n l o g n ) O(nlogn) O(nlogn)执行更久。小数据量排序,选择更简单、无需递归的插排。

哨兵来提高执行效率,在qsort()插入排序的算法实现中,虽然哨兵可能只是少做一次判断,但是毕竟排序函数是非常常用、非常基础的函数,性能的优化要做到极致。

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

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

相关文章

【算法】滑动窗口

目录1.概述2.算法框架3.应用本文参考: LABULADONG 的算法网站 1.概述 (1)滑动窗口可以用以解决数组/字符串的子元素相关问题,并且可以将嵌套的循环问题,转换为单循环问题,从而降低时间复杂度。故滑动窗口算…

【数据分析】(task5)数据建模及模型评估

note 文章目录note一、建立模型二、模型评估2.1 交叉验证2.2 混淆矩阵/recall/accuracy/F12.3 ROC曲线三、Pyspark进行基础模型预测时间安排Reference一、建立模型 下载sklearn的命令pip install scikit-learn。 from sklearn.model_selection import train_test_split impor…

ARP渗透与攻防(二)之断网攻击

ARP断网攻击 系列文章 ARP渗透与攻防(一)之ARP原理 1.环境准备 kali 作为ARP攻击机,IP地址:192.168.110.26 MAC地址:00:0c:29:fc:66:46 win10 作为被攻击方,IP地址:192.168.110.12 MAC地址:1c:69:7a:a…

Tkinter的Entry与Text

Tkinter界面设计之输入控件Entry以及文本框控件Text。 目录 一、放置控件 1. pack()函数 2. place()函数 3. grid()函数 二、简单控件 1. Entry输入控件 1.1 tk.StringVar()函数:接收一个字符串 1.2 tk.Entry()函数:设置一个输入控件E 2. Text文…

CMake多文件编译

之前学习ceres-solver中的3d相关的源码的时候,发现对于CMake多文件工程编译中对于CMakeLists.txt的编写和处理的理解运用还是比较模糊,这里整理梳理一下对于不同文件夹数量如何使用。 参考文章: CMake使用详解二(多文件编译&…

maya常用操作

1:重置工作区。2:切换视图。按空格切换视图。3:未选中状态,按shift,再点右键,可以打开交互式创建。这样可以在栅格上创建想要的大小。不选中交互式创建的话,创建的是默认未知。默认未知为正中间…

linux系统中利用QT实现车牌识别的方法

大家好,今天主要和大家分享一下,如何利用QT实现车牌识别的方法。 目录 第一:车牌识别基本简介 第二:车牌识别产品申请 第三:百度车牌识别API接口 第四:车牌识别综合测试 第一:车牌识别基本简…

Scala快速入门

Scala简介 Scala是一门现代的多范式编程语言,平滑地集成了面向对象和函数式语言的特性。Scala运行于Java平台(JVM,Java 虚拟机)上,并兼容现有的Java程序,Scala代码可以调用Java方法,访问Java字…

ArcGIS Pro脚本工具(17)——生成多分式标注

​朋友们,你们知道ArcGIS里面分式标注的四种写法么? 放错图了,是这个 分式标注的四种形式我们可以把这类叫分式标注,网上也有博主分享过如何在ArcGIS中制作这类标注,但我觉得仍有一些不足。 一是基本都使用VB编写&…

中文问题相似度挑战赛

赛题概要 请本赛题排行榜前10位的队伍,通过作品说明提交源代码,模型以及说明文档,若文件过大,可发送至官网邮箱AICompetitioniflytek.com, 若截止时间内为提交,官方会通过电话联系相关选手,若未接到通知或…

WPF作图神器Interactive DataDisplay的初步使用

文章目录安装初步使用安装 Interactive DataDisplay是一款比较优秀的C#绘图控件,尽管与一些商业控件还有不小的差距,关键是开源免费轻量。 在VS中安装控件十分简单,本测试基于Net Core5.0,在VS的菜单栏->工具->NuGet包管理…

HomeLab 常用工具一:filebrowser

前言在实际使用过程中,我们通常都有基于WEB 的文件操作需求(例如从一台陌生设备上想打开看一下,图片等),和nextcloud 相比 filebrowser 更为轻巧也更为方便。一、filebrowser 安装这里基于docker 安装和使用&#xff0…

Prometheus 动态拉取监控服务

Prometheus 版本 2.41.0 平台统一监控的介绍和调研直观感受PromQL及其数据类型PromQL之选择器和运算符PromQL之函数Prometheus 配置身份认证Prometheus 动态拉取监控服务 我们在以前的实例中配置Prometheus 的target 都是手动配置,这在监控目标少的情况下还可以接受…

【基础】BMP格式

BMP格式位图 (BMP)简介格式1.1图和调色板的概念1.2 bmp文件格式1.2.1 位图文件头 14字节1.2.2 位图信息头 40字节1.2.3 调色板1.2.4 注意位图 (BMP)简介 BMP取自位图Bitmap的缩写,也称为DIB(与设备无关的位图),是一种独立于显示器…

【苹果家庭群发推】软件keychain中刚打开的证书下载的证书文件要决不会报错 UNTimeIntervalNotificationTrigge

推荐内容IMESSGAE相关 作者✈️IMEAX推荐内容iMessage苹果推软件 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容1.家庭推内容 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容2.相册推 *** 点击即可查看作者要求内容信息作者✈️IMEAX推荐内容3.日历推 *** …

linux入门---linux基本指令

目录标题云服务器选择云服务器购买xshell下载如何登陆云服务器Linux的新建与删除新建删除云服务器选择 学习linux的时候云服务器是一个非常重要的工具,那么我们在购买云服务器的时候有很多选择比如说:华为云,腾讯云,阿里云等等&a…

活动星投票网络文明公益广告网络评选微信的投票方式线上免费投票

“网络文明公益广告”网络评选投票_不记名投票小程序_投票帮手免费畅享_扫码投票微信小程序手机互联网给所有人都带来不同程度的便利,而微信已经成为国民的系统级别的应用。现在很多人都会在微信群或朋友圈里转发投票,对于运营及推广来说找一个合适的投票…

ROS2机器人编程简述humble-第三章-PERCEPTION AND ACTUATION MODELS .1

书中,第三章主题:First Behavior: Avoiding Obstacles with Finite States Machines本节旨在应用到现在为止所展示的一切来创建看似“聪明”的行为。这个练习将介绍的许多东西结合起来,并展示使用ROS2编程机器人的效率。此外,将解…

第五届字节跳动青训营 前端进阶学习笔记(八)React框架入门

文章目录前言React 的设计思路1.传统JavaScript更新UI的痛点2.我们对UI代码的需求3.组件(1)组件定义(2)组件设计(3)组件结构4.React的生命周期React的基本语法1.JSXReact的实现1.虚拟DOM2.响应数据的实现前…

Java面试题,Spring Bean的注册与依赖注入

Spring Bean的注册与依赖注入一、XML文件中,将Bean创建到Spring容器1. 基本类型注册2. 类装配3. 有参构造方法装配4. 扩展注入5. Bean的作用域6. Bean的其他配置二、配置类中,将Bean创建到Spring容器1. 在mapper、service、controller中创建,…