其他分享
首页 > 其他分享> > 快速排序扫描分区法

快速排序扫描分区法

作者:互联网

一、快速排序单向扫描分区法

在这里插入图片描述

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