快排的2种分区图解
主要是找分区点后把小于分区点值的放在左边,大于分区点的放在右边
关键点是如何找到这个分区点应该放的位置
分区方式1
选取最右边的3做分区点 privot
把小于privot的放在左边
按照同样的逻辑处理左边区间的数据
把大于privot的放在右边
按照同样的逻辑处理右边区间的数据
假设要把privot放在i的位置
- 那么要有2个区间 ,最终实现的效果
- [p,i-1]放小于privot的元素
- [i+1,r] 放大于privot的元素
- i 放pivot
arr[i]是第一个大于privot的,在i之后都是大于privot的,
如果在遍历过程中发现了比privot小的数,
要把这个数与arr[i] 交换,同时i++才能保证arr[i]是第一个大于privot的位置
遍历[p,r-1] 把小于分区点arr[r]的放入到[p,r-1]
最后把分区点挪到分区点索引i,并返回i
下面是1个分区过程图
代码如下
int partition(int arr[],int p,int r){
int privot=arr[r];//分区点
int i,j; //arr[p,i-1]为已处理区间
i=p,j=p;
for(;j<r-1;j++){
if(arr[j]<privot){
int tmp=arr[i];
arr[i]=arr[j];
arr[j]=tmp;
i++;
}
}
arr[r]=arr[i];
arr[i]=privot;
return i;
}
分区方式2
两端指针
把其中的一个挖出来,作为分隔点,这端就会有1个坑
从另外1端开始,考察元素 ,大于分隔点的挖出这个元素 移动到另外1端的坑处,
没坑的这端向中间移动,考察这端的元素与privot...具体看下图
总之就是
1.挖坑
2.对端考察(与privot比较)
比较的结果是
1.向中央移动
继续与privot比较
2.挖出来填到对端坑,对端向中央移动,考察 移动或者挖出
这种方式的分区代码
function partition1(&$arr,$left,$right){
$privot=$arr[$right];
while($left<$right) {
while($arr[$left]<$privot && $left<$right){
$left++;
}
if($arr[$left]>$privot && $left<$right){
$arr[$right]=$arr[$left];
$right--;
}
while($arr[$right]>$privot && $left<$right){
$right--;
}
if($arr[$right]<$privot && $left<$right){
$arr[$left]=$arr[$right];
$left++;
}
}
$arr[$left]=$privot;
return $left;
}
在排序过程中 原有的大小顺序(456)被打乱,所以快排不是稳定排序算法