前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >高性能排序函数实现方案

高性能排序函数实现方案

作者头像
JavaEdge
发布2023-02-13 15:09:59
1K0
发布2023-02-13 15:09:59
举报
文章被收录于专栏:JavaEdgeJavaEdge

如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(n2) 情况概率不大。

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

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

4 总结

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

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

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

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

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

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

假设k=1000,c=200,当我们对小规模数据(比如n=100)排序时,n2的值实际上比knlogn+c还要小。

knlogn+c = 1000 * 100 * log100 + 200 >> 10000
n^2 = 100*100 = 10000

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

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-01-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1 合适的排序算法?
  • 2 归排分析
  • 3 优化快排
    • 最理想分区点
      • 3.1 三数取中法
        • 3.2 随机法
        • 4 总结
        领券
        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档