算法Day05 快速排序优化之三路快排

13 篇文章 0 订阅

从前天开始,学习了快速排序,快速排序是一门很优秀也经常会被用到的排序,所以昨天我们学习了快速排序的进阶版本,双路快排,但是除此之外,还能进行再度的优化,这就是我们今天要学习的,三路快排

What?三路?刚刚昨天学习了双路,怎么又蹦出个三路来了?这到底有多少路?

说实在话,昨天我学到这个的时候也是懵逼的,但是经过学习之后,我发现,其实三路和双路都是差不多的,双路排序是两个索引,那么显而易见,三路排序就是三个索引啦

下面我们来总结一下基础版,双路版,三路版的区别:

基础版:将数组分成小于和大于等于两个区间

双路版:将数组分成小于等于和大于等于两个区间

三路版:将数组分成小于,等于,大于三个区间

可以看出,三路版对于区间的划分更加的精细,那么如何去实现它呢?其实就是在双路版的基础上再加上一个索引

 

lt: 要保证在[ left , lt - 1] 这个区间上的元素都是小于value的

gt: 要保证在[ gt , right ] 这个区间上的元素都是大于value的

i: 就是我们当前所需要校验的位置

 

一定要注意边界问题,别问我为什么,血的教训,要注意区间两端的开闭

 

废话不多说,直接上代码:

 

package com.smarking.lzy.part1;
/*
 * 三路快速排序
 * 
 * 双路排序是两个索引,所以三路排序就是三个索引了
 * 单路和双路排序都是将区间划分成两个区域:小于(等于)参考值,大于(等于)参考值
 * 三路排序最终的结果就是将区间划分成三个区域:小于参考值,等于参考值,大于参考值
 * 
 * 所以我们这次返回的就是等于参考值的区间,我们返回一个数组,数组中存储两个元素,一个是等于我们参考值的区间的左边界,另外一个是右边界
 * arr[left + 1 ... lt] < value
 * arr[gt ... right] > value
 * arr[lt+1 ... i) == value
 * 
 * 边界很重要!!!问题出错都是处在边界的理解,一定要好好理解边界问题!
 * */
public class QuitSortThird {
	
	public static void sort(int [] arr ,int left ,int right) {
		//设置递归的出口
		if(left >= right) {
			return;
		}
		
		int [] positions = partition(arr,left,right);
		sort(arr,left,positions[0] - 1);
		sort(arr,positions[1],right);
	}
	
	//重点,返回等于参考值的区间
	private static int [] partition(int [] arr,int left,int right) {
		//创建一个数组,用来存储区间的左右边界,默认第一个存左边界,第二个存有边界

		
		int [] positions = new int[2];
		//随机选择一个位置作为参照值
		int index = (int) (Math.random() * (right - left + 1)+left);
		//int index = 6;
		SortTestHelper.swap(arr, left, index);
		int value = arr[left];
		
		//定义三个索引,分别是左边界,有边界和用来遍历的索引
		int i = left + 1;//用来遍历整个数组的索引
		int lt = left;//左边界
		int gt = right + 1;//右边界
		
		while(i < gt) {
			if(arr[i] < value) {
				SortTestHelper.swap(arr, i, lt + 1);
				
				i++;
				lt++;
			}else if(arr[i] > value) {
				SortTestHelper.swap(arr, i, gt - 1);
				gt--;
				//i++;这个地方不能自增,因为右边的元素都是没有进行遍历的,如果自增,就会跳过该元素
			}else {
				i++;
			}
		}
		
		SortTestHelper.swap(arr, left, lt);
		positions[0] = lt;
		positions[1] = gt;
		return positions;
	}
	
	
	public static void main(String[] args) {
		int testTime = 10000;
		int maxValue = 100;
		int maxSize = 10000;
		boolean success = true ;
		for(int i = 0;i < testTime;i++) {
			int [] arr1 = SortTestHelper.generateRandomArray(maxSize, maxValue);
			//int [] arr1 = {1 ,2 ,-1, 5 ,-2, 4, 2, 5 };
			int [] arr2 = SortTestHelper.copyArray(arr1);
			int [] arr3 = SortTestHelper.copyArray(arr1);
			sort(arr1,0,arr1.length-1);
			SortTestHelper.comparator(arr2);
			if(!SortTestHelper.isEqual(arr1, arr2)) {
				success = false;
				SortTestHelper.printArray(arr3);
				SortTestHelper.printArray(arr1);
				break;
			}
		}
		
		if(success) {
			System.out.println("Nice!!!");
		}else {
			System.out.println("Fuck!");
		}
	}

}

这两天就不学习新的算法了,先停下来巩固一下之前学的

这两天我会对之前的算法进行一个对比,然后我会尝试把这些算法结合在一起,使得他们的效率做到极致。

算法是一种长远的投资,我相信,肯定会有量变到质变的一天!

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值