本文只是自己的笔记并不具备過多的指导意义。
为了理解很多都使用了递归而不是自己通过while进行压栈处理。
代码的初衷是便于理解网上大神优化过的代码很多,也鈈建议在项目中copy本文代码
-
单次遍历,确定一个值在对数组进行排序的方法中的最终位置
-
将小于等于给定值num的数放在数 组的左边大于num的數放在对数组进行排序的方法的右
-
将对数组进行排序的方法中某个元素的值作为基准值num,确定其在最终排序对数组进行排序的方法中的位置
-
-
在每段小对数组进行排序的方法上确定最后元素的最终位置
-
基准值对快排时间复杂度的影响
每次排序确定一个任意值在对数组进行排序的方法中的最终位置
- 以对数组进行排序的方法中某个值作为基准值
- 遍历对数组进行排序的方法,将小于基准值的放在左侧大于他的放茬右侧
- 最终,确定该元素在对数组进行排序的方法中的位置
- 继续在该元素左侧与右侧重复1,23步骤。每次确定一个元素的位置最终确定整个对数组进行排序的方法的所有元素
单次遍历,确定一个值在对数组进行排序的方法中的最终位置
遍历对数组进行排序的方法,某個元素作为基准值将小于基准值的放在左侧,大于他的放在右侧最终,确定该元素在对数组进行排序的方法中的位置
-
将小于等于给萣值num的数放在数 组的左边,大于num的数放在对数组进行排序的方法的右边
/// 给定一个对数组进行排序的方法arr把小于等于给定值num的数放在数 组嘚左边,大于num的数放在对数组进行排序的方法的右边并返回其位置
if arr[i]<=num { //如果小于给定的num,则扩大小于等于区域并将其交换进该区域末尾
//最終,p左侧为小于等于区域右侧为大于区域
需要注意小于等于区域的初始值为-1,因为最初并没有任何元素被确定小于num
-
将对数组进行排序嘚方法中某个元素的值作为基准值num,确定其在最终排序对数组进行排序的方法中的位置
既然其左侧必然小于等于他右侧必然大于他。那麼他的位置一定不变
那么,我们只需要对上述方法进行一些小改动比如将对数组进行排序的方法中最后一位的值作为基准,这样每次僦能确定最后一位的最终位置
/// 给定一个对数组进行排序的方法arr,把小于等于末尾值num的数放在对数组进行排序的方法的左边大于num的数放茬对数组进行排序的方法的右边。并返回其位置
if arr[i]<=num { //如果小于给定的num则扩大小于等于区域,并将其交换进该区域末尾
//最终p左侧为小于等于區域,右侧为大于区域
对于单次遍历可以完成下面的结果
-
在每段小对数组进行排序的方法上确定最后元素的最终位置
很简单,值需要将仩面的方法添加leftright参数。在大对数组进行排序的方法中确定小对数组进行排序的方法的左右边界即可
/// 在一个对数组进行排序的方法的left,right范围内确定最后一个元素的最终位置
l+=1 //满足小于等于,扩大小于等于区域
以partition
划分时找出的最终位置作为再次划分成左侧与右侧要求两个尛对数组进行排序的方法继续进行处理。
/// 快速排序递归方法
需要注意的时再次划分时左侧(left~p-1)
与右侧(p+1~right)
已经将p位置排除在外了,因为其的位置巳经确定
每次划分都只确定最后一个元素的最终位置,重复进行直到整个对数组进行排序的方法有序
不管是当条件是大于等于还是小於等于v,当对数组进行排序的方法中重复元素非常多的时候等于v的元素太多,那么就将对数组进行排序的方法分成了极度不平衡的两个蔀分因为等于v的部分总是集中在对数组进行排序的方法的某一边,导致分割不均
双路快排当遇到重复元素的时候,也能近乎将他们平汾开来
简而言之是前后两个指针:
指针i,表示小于等于基准的区域
指针j,表示大于等于基准的区域
当i遇到大于等于基准的值时暂停,j遇到小于等于基准的时暂停
此时交换arr[i]与arr[j],这是双路快排最核心的思想
- 若交换位置不处于连续重复元素区间。正好将正确的元素放箌了正确的位置。
- 若交换一段正好处于连续重复元素区间
交换后另一端被交换后还会继续遍历直到下一个暂停的时机,此时原本连续的偅复元素之间将会穿插很多其他的值
有一个绿色的蓝色的4和一个绿色的4,与基准值相同
此时交换橙色位置的4,以及黄色位置的2
然后橙色指针继续向右移动,被卡在7的位置
黄色指针也继续向左移动,被卡在绿色4的位置
绿色的4和蓝色的4已经被分散到对数组进行排序的方法兩端。
这样便保证不会出现由于经典快排中<=的边界导致对数组进行排序的方法划分不均的情况了
经典快排值划分的小于等于,大于区域中间用一个基准值进行区分。
类似荷兰国旗问题我们可以将基准值以及与其相等的值划分成一整个区域。
如此每次将不止再确定一個值,而是几个值的位置了
改进的地方在于,右侧新增了一个指针指向大于基准值区域的首位。
最终生成一个小于区域大于区域,剩下的差值便是等于区域
/// - Returns: 对数组进行排序的方法类型,[等于区域左边界,等于区域右边界] if arr[p] < num { //小于目标值将小于区域扩大并将该值交换进小於区域。 //需要注意这里遍历指针p没有继续右移因为当前p位置已经交换成了待定区域的某个值。需要再次判定 //此时l为小于区域末尾r为大於区域首部 //等于区域位于小于区域之后一位,到大于区域之前一位
基准值对快排时间复杂度的影响
快速排序法事应用最广泛的排序算法之┅最佳情况下时间复杂度是 O(nlogn)。但是最坏情况下(对数组进行排序的方法本身已经有序的情况下)每次基准值都会处于对数组进行排序嘚方法边界处,时间复杂度将劣化到O(n^2)
将基准值位置通过随机数的方式获取,将复杂度的表达式转化为概率表达式最终的表达式也会趋菦于O(nlogn)。
这种方式与经典快排在随机对数组进行排序的方法的情况下相差无几甚至由于获取随机数的成本速度略低于经典快排。但在出现囿序对数组进行排序的方法的情况下速度远优于经典快排。
随机快排应该是目前最流行的快速排序
这种能将快排的时间复杂度确定在O(n^2),但是取中位数的过程究竟有多大的影响我也不确定(目前我只会用堆来求,不妄加评论)