基于荷兰国旗优化的快排

思路:

  1. 快排核心思想是递归的调用partition。具体来说,partition就是在待排数组arr选取一个数p作为比较的基准,小于等于的数放在左边,大于的数放在右边。然后继续对左右两部分继续分别调用partition过程。这是传统快排思想,其一般选取arr中最后一个元素作为比较的基准,递归调用的过程亦复如此。
  2. 为什么需要用荷兰国旗问题去优化快排过程呢?首先介绍荷兰国旗问题:与上述partition唯一的不同就是在于分为3个部分(小于,等于,大于),不将小于与等于合在一起。这样的好处在于一次可以处理多个基准值(因为arr中可能不止一个值是p,如果按照传统partition,那么和可能多次会处理以p作为基准值的情况,下图第二次仍以5为基准做划分)的位置,一定程度优化排序速度。
    图1
    实现:
    1. 我们希望partition过程返回arr的一个范围,这个范围就是这一次(因为会递归调用)partition中待排序arr中等于基准值元素的范围,即下图中[less+1, more-1](这里的less和more是两个指针,less指向最后一个小于基准p的位置,more指向第一个大于基准p的位置),对于[10, 9, 8, 7, 5, 5, 5, 4, 3, 2](举例;已完成partition后的arr)应该返回[4, 6]。
      图2
    2. 所以核心就是实现优化的partition过程:我们先选取arr中最后一个元素作为基准值p(这里可通过随机化去优化),再初始化4个指针less=l-1,more=r+1。其中,l、r分别指arr中待partition的范围,同时l也作为当前指针往前走(判断的意思)。
      i)当arr[l]<p,交换arr[less+1](less后面一个元素,因为less已经确保在其之前的元素均小于p)与arr[l]位置,同时l、less继续往后走;
      ii)当arr[l]>p,交换arr[more-1](more前面一个元素,因为more已经确保在其之后的元素均大于p)与arr[l]位置,同时more继续往前走(此时l的位置不变,继续比较交换后的元素与p大小);
      iii)当arr[i]=p,i继续往后走;
      iv)停止条件:当前指针l碰到more。
      图3
package _02基于荷兰国旗优化的快排;

import java.util.Scanner;

/**
 * 传统的快拍是把小于等于最右边数p的数放在左边,大于p的数放在右边,所以
 * 它一次只处理一个p,当待排序数组arr有多个p,那当前就不管,就只处理一个位置的p。
 * 而荷兰国旗返回的是等于p的范围,所以就把arr中等于p的位置都处理好了,速度会比
 * 传统快拍快一点。
 */
public class QuickSort {
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		int[] a = new int[10];
		for(int i=0;i<a.length;i++) {
			a[i] = in.nextInt();
		}
		sort(a, 0, a.length-1);
		print(a);
	}

	private static void print(int[] res) {
		for(int i=0;i<res.length;i++) {
			System.out.print(res[i]+" ");
		}
		System.out.println();
	}

	private static void sort(int[] a, int l, int r) {
		if(l<r) {
			int[] p = partition(a, l, r);
			sort(a, l, p[0]-1);
			sort(a, p[1]+1, r);
		}
	}
	
	private static int[] partition(int[] a, int l, int r) {
		int less = l-1;
		// 这里不使用more=r+1是因为不用一个单独的空间存储基准值
		// 而是直接使用a中最后一个元素。区别就是more的范围首先就把
		// a中最后一个元素包括进去,待partition完成后,再交换more与
		// a中最后一个元素的位置,那么返回的位置就变成了[less+1, more]
		// 这时more+1才是原来more的位置。
		int more = r;
		while(l<more) {
			if(a[l]<a[r]) {
				swap(a, l++, ++less);
			}
			else if(a[l]>a[r]) {
				swap(a, l, --more);
			}
			else l++;
		}
		swap(a, more, r);
		return new int[] {less+1, more};
	}

	private static void swap(int[] a, int i, int j) {
		if(a[i]==a[j]) return;
		a[i] = a[i] ^ a[j];
		a[j] = a[i] ^ a[j];
		a[i] = a[i] ^ a[j];
	}
}

猜你喜欢

转载自blog.csdn.net/zyd196504/article/details/87954669