算法Day04 快速排序优化之随机双向快排

昨天学习了快速排序,回顾一下,快速排序的做法就是一次排序将一个数放到正确的位置上,并返回当前位置的索引,然后避开此位置,对其他位置进行重复的排序,有点像前边学到的归并排序,不知道大家有没有印象。

归并排序和快速排序的思想都是递归分割,然后对分割出来的区域进行排序,但是有一个不同的地方就是,归并排序每次分割都会平均分成二等分,但是快速排序却十分的不稳定,最理想的情况就是能和归并排序一样,找到一个中间数字,但是试想,如果数组是排好序的,而我们如果还是以第一个元素作为参考值,那么每次都需要遍历整个数组,那么这时候快速排序就退化到了O(n²)级别的算法了

 

为了防止这种情况发生,我们不再使用第一个元素作为参照,而是适合用一个随机生成的数字作为参照数的下标,这样就防止了上述情况的发生。

 

并且采用双头共进的方式进行优化

所谓的双头共进,就是分别创建两个索引,从两端开始进行遍历。左边的索引寻找比参照数大的元素,右边的索引寻找比参照数小的元素,找到之后交换位置,然后继续重复上述操作,直至到达我们设置的边界,这样又进一步提高了效率

 

废话不多说,直接上代码

package com.smarking.lzy.part1;

/*
 * 随机双向快排
 * 
 * 
 * 
 * */
public class QuitSortRandom {
	
	public static void sort(int [] arr,int left,int right) {
//		if(right - left < 15) {
//			
//		}
		
		if(left >= right) {
			return;
		}
		
		int p = partititon(arr,left,right);
		sort(arr,left,p-1);
		sort(arr,p+1,right);
	}
	
	private static int partititon(int [] arr,int left,int right) {
		int index = (int) (Math.random() * (right - left + 1)+left);
		SortTestHelper.swap(arr, left, index);
		int value = arr[left];
		int i = left + 1;
		int j = right;
		while(true) {
			while(i <= right && arr[i] < value) {
				i++;
			}
			
			while(j >= left + 1 && arr[j] > value) {
				j--;
			}
			
			if(i > j) {
				break;
			}
			
			SortTestHelper.swap(arr, i, j);
			i++;
			j--;
		}
		SortTestHelper.swap(arr, left, j);
		return j;
	}
	
	public static void main(String[] args) {
		int testTime = 1;
		int maxValue = 100;
		int maxSize = 5;
		boolean success = true ;
		for(int i = 0;i < testTime;i++) {
			//int [] arr1 = SortTestHelper.generateRandomArray(maxSize, maxValue);
			int [] arr1 = {-43 ,90 ,9 ,-4 ,3,4 };
			int [] arr2 = SortTestHelper.copyArray(arr1);
			sort(arr1,0,arr1.length-1);
			SortTestHelper.comparator(arr2);
			if(!SortTestHelper.isEqual(arr1, arr2)) {
				success = false;
				SortTestHelper.printArray(arr1);
				SortTestHelper.printArray(arr2);
				break;
			}
		}
		
		if(success) {
			System.out.println("Nice!!!");
		}else {
			System.out.println("Fuck!");
		}
	}


}

 

点赞