14 | 排序优化:如何实现一个通用的、高性能的排序函数?

一、如何选择合适的排序算法?

线性排序算法时间复杂度低,适用场景比较特殊。所以选择一个通用的、高性能的排序算法,不能选用线性排序。
小规模的数据排序,选用时间复杂度是O(n²)的算法;大规模数据进行排序,时间复杂度是O(nlogn)的算法更加高效。为了兼顾任意规模数据的排序,一般都会首选时间复杂度是O(nlogn)的排序算法来实现排序函数。
时间复杂度是O(nlogn)的排序算法:归并排序、快速排序(C语言的排序函数)、堆排序(Java语言的排序函数)。

归并算法时间复杂度优于快排,为什么没有被大量应用吗?
归并的平均情况和最坏情况下的时间复杂度都是O(nlogn),但快排的最坏情况时间复杂度是O(n²)。为什么归并没有被大量应用?归并空间复杂度是O(n),不是原地排序算法。即除数据本身内存大小外,还要额外占用和数据一样大小的内存。

二、如何优化快速排序?

2.1、如何优化快速排序最坏情况下的时间复杂度O(n²)呢?

**出现这种情况的描述:**数据完全或接近有序,每次分区点选择最后一位。
**原因是:**分区点选的不够合理。

如何选出好的分区点?

**最理想的分区点是:**被分区点分开的两个分区中,数据的数量差不多。
根据数据特征去选分区点,而不是粗暴的选第一个或者最后一个。

两个常用、简单的分区算法

1、三数取中法
从数据的头、尾、中取出数后,进行比较取中间数为分区点。如果数组比较大,那还可以“五数取中”或者“十数取中”。

2、随机法
在数据中随机选择一个作为分区点,虽然不能选到最合适的分区点,但是从概率来讲选到最坏的分区点也不容易。

解决快速排序的递归过深导致堆栈溢出的两种方式

第一种:限制深度。一旦递归超过我们预设的阈值,就停止递归。

第二种:(没明白)通过在堆上模拟实现一个函数调用栈,手动模拟递归压栈、出栈的过程,这样就没有了系统栈大小的限制。

O(n²)时间复杂度的算法并不一定比O(nlogn)的算法执行时间长

算法的性能通过时间复杂度来分析衡量,但是这个分析比较偏理论。仔细深究的话,时间复杂度并不等于代码实际的运行时间。
时间复杂度代表的是一个增长趋势图。O(n²)比O(nlogn)要陡峭,增长趋势要猛。
如果不忽略低阶、系数和常数。O(nlogn)=O(knlogn+c),k和c有可能还是一个比较大的数。举一个具体的例子:
k=1000,c=200,n=100

knlogn+c = 1000 * 100 * log100 + 200 远大于10000
n^2 = 100*100 = 10000

可以看出O(n²)要比O(nlogn)的值要小。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值