快排优化(继三数取中、插入排序优化后的再优化)

发布于:2024-07-19 ⋅ 阅读:(163) ⋅ 点赞:(0)

之前排序内容概述

这是之前的****快速排序*****讲解,主要讲解了三种算法(霍尔版本,挖坑法,前后指针法),然后是递归版本和非递归版本,用非递归版本主要是为了解决栈溢出的问题,但是却不能解决某些情况时间复杂度坍缩成O(N²),例如当待排数据已经有序的时候就会坍缩,就产生了三数取中的方法,尽可能的让每次排序左右均分。

新问题

但是还是有一定的问题,比如全是同样的数据时也会坍缩,因为三数取中无论怎么取都是一样的,不起效果。

那么就有另一种算法来完成子排序:

三路分化

三路分化原理

A.我们以arr[0]的数据作为K,即一次排序的中间值,左边比它小右边比它大。

B.这里创造三个指针,left指向开头,cur指向left下一个下标,right指向末尾下标。

C.我们的cur会扫遍整个数组,直到超过right指针。

D.cur的运动过程是:如果此时 arr[cur]<K  就让left的值和cur的值交换,并让left和cur向后移动一格;如果此时  arr[cur]==K  那么就只让cur向后移一位;如果此时  arr[cur]>K  就让cur的值和right的值交换,并让right向左移,而cur不移动。结果就是cur继续和right交换,然后重复操作,直到cur和right交换后cur的值不再大于K为止。那么就会进行前两个操作,cur就继续往后移动了。

我们看了D这个过程后,就可以总结出,left之前的是比K小的,left和cur之间的是等于K的,right之后的是大于K的。并且发现left的值始终等于K。

我们通过下面的GIF来看看整个过程

代码实现

优点

三路分化的优点就是将重复的K数据直接放在中间,之后的子排序不再参与。

那么重复度大的数据进行排序就会省很多事。

三路分化优化

我们将cur与right进行交换的时候,这个过程可能持续很多次,因为换过来的值可能还是比K要大,所以我们可以让right往左移一直找到小于等于K的数值,再进行交换。这样就减少了交换的次数。

这个我测过,没有这个之前在力扣里面是过不了的,写了就能过了。

自省排序

虽然上面的可以解决很多种情况,但是还是不能100%的排除栈溢出的风险,所以就有了自省排序。

我们每次递归就让一个传入值deep加一来记录递归的深度,如果deep>2*hight就可以换成堆排序,这个结论是前人通过大量实验的出来的。这里的hight表示的是这次递归的最大深度。

那么我们通过以上代码就可以实现了,通过下面的for循环来求hight=log(r-l+1),让后我们核心排序可以用前后指针等都行,因为如果递归次数过深都会调用堆排


网站公告

今日签到

点亮在社区的每一天
去签到