快速排序扫描分区法
作者:互联网
一、快速排序单向扫描分区法
static void quickSort(int[] arr,int begin,int end) {//分成若干个左子问题,右子问题
if(begin<end) {
int q = partition(arr,begin,end);
quickSort(arr, begin, q-1);
quickSort(arr, q+1, end);
}
}
那么重点就是如何去划分,左边的比主元小于或等于,右边的比主元大
代码思路
扫描指针小于等于主元的时候扫描指针往后走
扫描指针大于主元的时候扫描指针的值和末指针交换,末指针向左走
static int partition(int[] arr,int begin,int end){
int pivot = arr[begin];
int left = begin+1;
int rigth = end;
while(left >= end){//左右两个指针错开时退出
if(arr[left] <= pivot){//左指针小于等于主元左指针++
left++;
}else{//大于的时候和末指针交换,末指针++
int t = arr[left];arr[left] = arr[rigth];arr[rigth]=t;
rigth--;
}
}//左指针最后一次一定在大于主元的值上
//右指针最后一次一定在小于等于主元的值上
//所以循环退出后主元和右的值交换
int t = arr[rigth];arr[rigth] = arr[begin];arr[begin]=t;
return rigth;
}
完整代码
public class _快速排序单向扫描分区法 {
public static void main(String[] args) {
int[] arr = util.getRandomArr(10, 1, 20);
quickSort(arr,0,arr.length-1);
System.out.println(Arrays.toString(arr));
}
static void quickSort(int[] arr ,int begin,int end) {
if(begin<end) {
int q = partition(arr,begin,end);
quickSort(arr,begin,q-1);
quickSort(arr,q+1,end);
}
}
//切一刀,确定主元,左边必然比主元小,右边必然比主元大
static int partition(int[] arr,int begin,int end) {
int pivot = arr[begin];
int sp = begin + 1;
int bigger = end;//两个值必然是相交错开的
while(sp <= bigger) { //前后两个指针错开
if (arr[sp] <= pivot) { //扫描指针小于主元,指针前进
sp++;
}else {//大于主元 则扫描指针的值和bigger值交换 bigger指针前进
util.swap(arr, sp, bigger);
bigger--;
}
}
util.swap(arr, begin, bigger);//最后一次两个指针重合比较指针的值,不管是大于还是小于
return bigger;
}
/*
* 最后一次两个指针重合比较指针的值
* 不管是大于还是小于
* 如果是大于 sp 则++,主元比较大,主元和 重合值 交换 bigger 主元左边是比主元小的
* 如果是小于 bigger-- 主元比较小, 那么就是 重合值-- 得左边一个交换
* 总结 :大于 主元 交换 重合值
* 小于 主元 交换 重合值左边一个交换
*/
}
二、快速排序双向扫描分区法
和一遍分区法是一样的,定义主元,左右指针
1.左指针的值小于等于主元那么就一直往右走,最后一次一定是大于主元的
2.右指针的值大于主元那么就一直往左走,最后一次肯定是小于主元的
3.把他们两个的值交换,
4.注意:一定是先左再右
代码实现
主要是更改partition方法,快速排序的方法不变
//快速排序
static void quickSort(int[] arr,int begin,int end) {//分成若干个左子问题,右子问题
if(begin<end) {
int q = partition(arr,begin,end);
quickSort(arr, begin, q-1);
quickSort(arr, q+1, end);
}
}
partition方法
static int partition(int[] arr,int begin,int end) {
int pivot = arr[begin];
int left = begin+1;
int rigth = end;
while(left <= rigth) {//前后两个指针交错开
while(left <= rigth && arr[left] <= pivot)left++;//left一定在大于主元的下标上面
while(left <= rigth && arr[rigth] > pivot)rigth--;//rigth一定在小于等于主元的下标上面
if(left < rigth)
util.swap(arr, left, rigth);
}
//循环结束,left一定在大于主元的位置上,rigth一定在小于等于主元的位置上
util.swap(arr, begin, rigth);
//最后把主元的位置返回
return rigth;
}
三、快速排序三指针分区法
Less 第一个等于主元的下标
Scan 扫描指针
Bigger 末指针 末指针右边一定是大于主元的
主元 | Less和Scan | ? | ? | ? | ? | ? | ? | ? | ? | ? | ? | Bigger |
---|
首先要找到第一个等于主元的下标
Scan小于主元 Scan ++
Scan大于主元 Scan <=> Bigger交换 Bigger–
Scan等于主元 Less = Scan Scan++ 跳出循环
这样我们就找到了第一个等于主元的下标
第一个循环
小于主元 ①扫描指针++
大于主元 ①扫描指针和末指针交换值 ②末指针–
等于主元 ①less就等于扫描指针 ②扫描指针++ ③跳出循环
/*第一个循环
* 小于主元 ①扫描指针++
* 大于主元 ①扫描指针和末指针交换值 ②末指针--
* 等于主元 ①less就等于扫描指针 ②扫描指针++ ③跳出循环
*/
while(Scan <= Bigger) {
if(arr[Scan]<pivot) {
Scan++;
}else if(arr[Scan]>pivot) {
util.swap(arr, Scan, Bigger);
Bigger--;
}else {
Less = Scan;
Scan++;
break;
}
}
第二个循环
等于主元 ①扫描指针++
小于主元 ①扫描指针和Less交换 ②Less++ ③因为扫描指针当前的值是等于主元的所以扫描指针++
大于主元 ①扫描指针和末指针交换 ②末指针–
/*第二个循环
* 等于主元 ①扫描指针++
* 小于主元 ①扫描指针和Less交换 ②Less++
* ③因为扫描指针当前的值是等于主元的所以扫描指针++
* 大于主元 ①扫描指针和末指针交换 ②末指针--
*/
while(Scan <= Bigger) {
if(arr[Scan]==pivot) {
Scan++;
}else if(arr[Scan]<pivot) {
util.swap(arr, Scan, Less);
Less++;
Scan++;
}else {
util.swap(arr, Scan, Bigger);
Bigger--;
}
}
完整代码
static int[] partition(int[] arr,int begin,int end) {
int pivot = arr[begin];
int Scan = begin+1;//第一个等于主元的
int Less = begin+1;//最后一次一定是指向大于主元的
int Bigger = end;//最后一次一定是等于主元的
/*第一个循环
* 小于主元 ①扫描指针++
* 大于主元 ①扫描指针和末指针交换值 ②末指针--
* 等于主元 ①less就等于扫描指针 ②扫描指针++ ③跳出循环
*/
while(Scan <= Bigger) {
if(arr[Scan]<pivot) {
Scan++;
}else if(arr[Scan]>pivot) {
util.swap(arr, Scan, Bigger);
Bigger--;
}else {
Less = Scan;
Scan++;
break;
}
}
//如果没有重复的那么上面那个while就可以解决,这里就可以返回了
if(Scan > Bigger) {
util.swap(arr, begin, Bigger);
return new int[] {Bigger,Bigger};
}
/*第二个循环
* 等于主元 ①扫描指针++
* 小于主元 ①扫描指针和Less交换 ②Less++
* ③因为扫描指针当前的值是等于主元的所以扫描指针++
* 大于主元 ①扫描指针和末指针交换 ②末指针--
*/
while(Scan <= Bigger) {
if(arr[Scan]==pivot) {
Scan++;
}else if(arr[Scan]<pivot) {
util.swap(arr, Scan, Less);
Less++;
Scan++;
}else {
util.swap(arr, Scan, Bigger);
Bigger--;
}
}
util.swap(arr, begin, Less-1);//less是第一个等于主元
return new int[] {Less-1,Bigger};//less 是等于主元的 less-1 是主元
}
考虑到不一样所有的数组都有重复值,所以我在中间加了一个判断
整体如下
public class _快速排序三分法 {
public static void main(String[] args) {
int[] arr = util.getRandomArr(1000, 1, 5);
quickSort(arr, 0, arr.length-1);
System.out.println(Arrays.toString(arr));
}
static void quickSort(int[] arr,int begin,int end) {
if(begin<end) {
int[] q = partition(arr,begin,end);
quickSort(arr, begin, q[0]-1);
quickSort(arr, q[1]+1, end);
}
}
static int[] partition(int[] arr,int begin,int end) {
int pivot = arr[begin];
int Scan = begin+1;//第一个等于主元的
int Less = begin+1;//最后一次一定是指向大于主元的
int Bigger = end;//最后一次一定是等于主元的
/*第一个循环
* 小于主元 ①扫描指针++
* 大于主元 ①扫描指针和末指针交换值 ②末指针--
* 等于主元 ①less就等于扫描指针 ②扫描指针++ ③跳出循环
*/
while(Scan <= Bigger) {
if(arr[Scan]<pivot) {
Scan++;
}else if(arr[Scan]>pivot) {
util.swap(arr, Scan, Bigger);
Bigger--;
}else {
Less = Scan;
Scan++;
break;
}
}
//如果没有重复的那么上面那个while就可以解决,这里就可以返回了
if(Scan > Bigger) {
util.swap(arr, begin, Bigger);
return new int[] {Bigger,Bigger};
}
/*第二个循环
* 等于主元 ①扫描指针++
* 小于主元 ①扫描指针和Less交换 ②Less++
* ③因为扫描指针当前的值是等于主元的所以扫描指针++
* 大于主元 ①扫描指针和末指针交换 ②末指针--
*/
while(Scan <= Bigger) {
if(arr[Scan]==pivot) {
Scan++;
}else if(arr[Scan]<pivot) {
util.swap(arr, Scan, Less);
Less++;
Scan++;
}else {
util.swap(arr, Scan, Bigger);
Bigger--;
}
}
util.swap(arr, begin, Less-1);//less是第一个等于主元
return new int[] {Less-1,Bigger};//less 是等于主元的 less-1 是主元
}
}
Tin know
发布了7 篇原创文章 · 获赞 12 · 访问量 220
私信
关注
标签:arr,Scan,int,分区,扫描,主元,排序,指针 来源: https://blog.csdn.net/Tinknow324/article/details/104576890