package com.wj;

import java.util.Arrays;

public class Sort {

	public static void main(String[] args) {
//		int[] a = {1,2,3,4,9,8,7,6,5,0,1,3,0};
		int[] a = {1,2,3,4,9,8,7,6,5,0,8};
		//		int[] a = {4,5,6,3,2,1};
		//		test1(a);
		//		test2(a);
		//		test3(a);
		//		test4(a);
		//		test5(a);
		test6(a);
//		test7(a);
		System.out.println(Arrays.toString(a));
	}

	/**
	 * 冒泡排序
	 * @param a
	 */
	private static void test1(int[] a){
		int len = a.length;
		for (int i = 0; i < len; ++i) {
			for (int j = 0; j < len - i - 1; ++j) {
				if (a[j] > a[j + 1]) {
					swap(a, j, j + 1);
				}
			}
		}

	}

	/**
	 * 插入排序
	 * @param a
	 */
	private static void test2(int[] a){
		int len = a.length;
		for (int i = 1; i < len; ++i) {
			int tmp = a[i];
			int j = i - 1;
			for (; j >=0; --j) {
				if (a[j] > tmp) {
					a[j + 1] = a[j];
				} else {
					break;
				}
			}

			a[j + 1] = tmp;
		}
	}

	/**
	 * 选择排序
	 * @param a
	 */
	private static void test3(int[] a){
		int len = a.length;
		for (int i = 0; i < len - 1; i++) {
			int min = i;
			for (int j = i; j < len; j++) {
				if (a[j] < a[min]) {
					min = j;
				}
			}

			if (min > i) {
				swap(a, i, min);
			}
		}
	}

	/**
	 * 归并排序
	 * @param a
	 */
	private static void test4(int[] a){
		int len = a.length;
		//		merge(a, 0, len - 1);
		merge2(a, 0, len - 1);
	}

	/**
	 * 快速排序
	 * @param a
	 */
	private static void test5(int[] a){
		int len = a.length;

		quick(a, 0 , len - 1);

	}

	/**
	 * 双路快速排序
	 * @param a
	 */
	private static void test6(int[] a){
		int len = a.length;
		quick2(a, 0, len - 1);
	}

	/**
	 * 三路快速排序
	 * @param a
	 */
	private static void test7(int[] a){
		int len = a.length;
		quick3(a, 0, len - 1);
	}


	private static void quick3(int[] a, int l, int r) {
		
		if (l >= r) return;
		
		int[] p = getP3(a, l , r);
		quick2(a, l, p[0]);
		quick(a, p[1], r);
		
	}
	
	private static int[] getP3(int[] a, int l, int r) {
		int v = a[l];
		int i = l;
		int j = r + 1;
		int k = l + 1; 
		while (k < j) {
			if (a[k] < v) {
				swap(a, k++, ++i);
			} else if (a[k] > v){
				swap(a, k, --j);
			} else {
				++k;
			}
			
		}
		swap(a, l, i--);
		return new int[]{i, j};
	}
	
	private static void quick2(int[] a, int l, int r) {

		if (l >= r) return;

		int p = getP2(a, l , r);
		quick2(a, l, p - 1);
		quick(a, p - 1, r);

	}

	private static int getP2(int[] a, int l, int r) {
		int v = a[l];
		int i = l + 1;
		int j = r;
		while(true){

			while (i < j && a[i] < v) {
				++i;
			}

			while (j > i && a[j] > v) {
				--j;
			}
			if (i == j) break;
			swap(a, i++, j--);
		}
		swap(a, i, l);
		return i;
	}

	private static void quick(int[] a, int l, int r) {
		if (l >= r) return;

		int p = getP(a, l, r);

		quick(a, l, p - 1);
		quick(a, p + 1, r);
	}

	private static int getP(int[] a, int l, int r) {
		int v = a[l];
		int i = l;
		for (int j = l + 1; j <= r; ++j) {
			if (a[j] < v) {
				swap(a, i + 1, j);
				++i;
			}
		}
		swap(a, l, i);
		return i;
	}

	/**
	 * 自底向上排序
	 * @param a
	 * @param left
	 * @param right
	 */
	private static void merge2(int[] a, int left, int right) {
		for (int i = 1; i < right; i += i) {
			for (int j = 0; j + i <= right; j += 2 * i) {
				mergeSort(a, j, j + i - 1, (j + 2 * i - 1 > right ? right : j + 2 * i - 1));
			}
		}
	}



	/**
	 * 自顶向下排序
	 * @param a
	 * @param left
	 * @param right
	 */
	private static void merge(int[] a, int left, int right) {

		if (left >= right) return;

		int mid = left + (right - left ) / 2;

		merge(a, left, mid);
		merge(a, mid + 1, right);

		mergeSort(a, left, mid, right);

	}

	private static void mergeSort(int[] a, int left, int mid, int right) {

		int[] tmp = Arrays.copyOfRange(a, left, right + 1);

		int i = left;
		int j = mid + 1;

		for (int k = left; k <= right; ++k ) {

			if (i > mid) {
				a[k] = tmp[j - left];
				++j;
			} else if (j > right) {
				a[k] = tmp[i - left];
				++i;
			} else if (tmp[i - left] < tmp[j - left]) {
				a[k] = tmp[i - left];
				++i;
			} else {
				a[k] = tmp [j - left];
				++j;
			}
		}

	}

	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];
	}
}