文章      动态     相关文章     最新文章     手机版动态     相关动态     |   首页|会员中心|保存桌面|手机浏览

06mhzm

http://fabua.ksxb.net/com06mhzm/

相关列表
文章列表
  • 暂无文章
推荐文章
联系方式
  • 联系人:赵先生
  • 电话:18321128505
快速排序及优化
发布时间:2024-12-20        浏览次数:0        返回列表

冒泡排序和快速排序都属于交换排序,其中快排更像是冒泡的进化版本,我们先看冒泡排序

快速排序及优化

思想:每轮循环将本轮最大元素移动到数组末尾,以此类推,直到长度为一。假设数组长度为 n,第一轮循环将最大元素移动到下标为 n-1 的位置,第二轮需要判断前 n -1 个元素,并将最大元素移动到 n-2 的位置,以此类推。计算最大值通过比较交换完成。

 

快排在冒泡的基础上做了优化,它不在局限于每轮找最大的或最小的,而是找比它小的和比它大的。每次将比它小的元素放在自身左边,比它大的元素放在右边,从全局层面保证有序。

思想:以数组下标开始元素为基准,比较交换。交换后左边都是比自己小的元素,右边都是比自己大的元素。左集合和右集合再分别进行上述判断,直到集合中只有一个元素。

 

从代码可以看出:quickSort() 计算出的 index 越靠近中心,递归的次数越少,性能越好。如果每次计算出的中点恰好都在中间,那时间复杂度仅为 O(nlog2n)。如果每次计算出的中点恰好都在边沿,时间复杂度为 O(n^2),和冒泡排序相等。

通常情况下由于数组无序,冒泡排序的时间复杂度约处于 O(nlog2n)。但当数组本身有序时,由于快排总拿第一个元素作为基准数,这样计算出的 index 总在边沿,时间复杂度非常高。为了解决该问题,可以从基准数的选择优化快排,通常有两种方式优化

  • 三数取中间数
  • 随机选基准数

优化后的代码如下

 

new Random().nextInt(n):返回小于 n 大于等于 0 的所有整数

只要保证选择的基准数尽可能的可以将数组划分为平均的两部分,就可以提高快排的性能


quickSort() 在满意 left <= right 条件时总要进行递归计算,当数组长度很小时,快排的效率可能不如冒泡排序,因为此时时间复杂度相等但快排涉及到创建栈的消耗。此时就可以优化,当数组长度很小时,直接采用冒泡排序

 

假设数组中存在多个和基准数相同的数,目前的逻辑相等不交换,从全局维度来说,划分的并不是很干净,举个例子

 

从结果来说,虽然左边全部是小于等于它的,右边全部是大于等于它的,但两者都包含和相等值,后续递归过程中仍需判断。我们可以想办法让相等的值集中在中间,这样下轮循环就可以不判断这部分值了,拿上面的例子来说,理想状态为分割为 432 555 68,下次只需递归 432 和 68 集合即可,下面我给出聚合以及跳过的逻辑

 

至此关于快排的三种优化介绍完毕

  1. 基准数选择优化
  2. 小数组采用其它排序方式,如插入、冒泡
  3. 基准数相等聚合跳过

最后由于快排采用分治的思想,单次任务实际上可以分配到不同的线程执行:对于每次任务,创新新线程执行,线程体就是快排的实现逻辑,把递归改为创建新线程执行即可,充分发挥 CPU 效率