快速排序的优化

优化1

通过时间复杂度来切入看看,最好情况为nlog2n,最坏情况为n^2。是什么导致差距如此之大呢?

 
最好情况就是每次分段的时候,那个分段的点都在待分段数列的中间位置,因此分布非常的平均,所有分段路线,也就是递归的层次是
一样的。大家同时分到每段是1个数据的层次。
 最坏情况就是顺序,每次分都是左边有,右边没有,导致右边很快就分完了,左边却一直往下分,最后就变成了0n^2。
  如何解决这种问题呢?那就是
 让分的点靠拢分段数列的中间。如何做到呢?我们都知道每次中枢点选的都是下标startIndex的值,谁能保证第一个位置的值的大小呢?
因此我们做了点手脚,找出数列中大小较中等的数赋给中枢点。怎么找,那就取中找呗。书上都是几分取中几分取中的。其实几分取中都是可以的
取的中其实还可能是大小比较偏的值,但数据一多,每个段都取中,那就会平均这种意外情况。
因此我们就使用3分取中吧。所谓三分取中也就是让数列中最左最右最中的三个值,呈顺序排列,然后让中间那个的值成为枢轴点。
(以前我们总让第一个数成为枢轴点), 这样就会使枢轴点  为大小太偏的数
的可能性降低。具体实现只需要在Quick()中前几行加入几行代码,这几行代码的效果是,取左中右3个点,比较他们大小,让中间的midIndex对应的值是不大不小的,然后让它成为枢轴点。
代码如图
快速排序的优化(-)

其实这里还有个小优化就是
while(i
   { while(i < j
&& arr[j]>=tmp)
 j--;
 arr[i]=arr[j];
 while(i < j &&
arr[i]<=tmp)
 i++;
 arr[j]=arr[i];
}
这里,我当初写基本快排的时候就是这样子,其实原始的是这个样子
 while(i
   { while(i < j
&& arr[j]>=tmp)
 j--;
swap(arr,i,j);
 while(i < j &&
arr[i]<=tmp)
 i++;
swap(arr,i,j);
}
区别就是把swap(arr,i,j)换成了直接赋值arr[i][j];
如果进行swap的话会进行很多重复操作,

而直接赋值的话虽然初次接触会难理解点,但却节省了很多不必要的数据交换



优化2

之前也讲过快速排序对于很多数据的数列来说。它优势很大,但如果数列数据很少,它甚至还不如简单排序来的快。那么由这点受到启发,我们知道快速排序是不断将数据分段的,分着分着最后数列就越来越短,快速排序的弊端也渐渐显露出来,那么如何防止这种事发生呢?

那当然是取长补短了!既然数列短的时候太慢,那我就不用快排了,用简单排序!不是说简单排序处理小数列快吗,那就在我数列很短的时候使用插入排序。把自己的短处给舍弃了,然后长处也还保持着,这种优化多厉害呢。至于到多短才算短呢?10?20?还是100?这个我们其实不深究数学原理也不容易搞得清楚,所以直接按某些书上推荐的值吧,就拿7来算吧。
当e-s>7的时候,我们照常使用分段递归Quick();当小于等于7的时候进入else,使用特制的插入排序
插入排序比起以前不同的是,对里面一些循环开始量和哨兵位做了修改,适应了一个数组中任何分段的数列进行 插入排序。
代码如下:
快速排序的优化(二)

这就防止了大材小用。杀鸡用牛刀的问题。不得不佩服总结出这些优化的先驱们。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值