Sort and Shuffle 排序和打乱

排序可视化

Sort 排序:


定义数组排序的基本方法:

public abstract class ArraySort {
	public static boolean INCREASE = true;
	public static boolean DECREASE = false;

	protected static <T extends Comparable<? super T>> boolean compare(T a,
			T b, boolean order, Comparator<T> comparator) {
		int cmp = COMPARE(a, b, comparator);
		if (order == INCREASE) {
			return cmp < 0;
		} else {
			return cmp > 0;
		}
	}

	public static <T extends Comparable<? super T>> int COMPARE(T a, T b,
			Comparator<T> comparator) {
		if (comparator != null) {
			return comparator.compare(a, b);
		} else {
			return a.compareTo(b);
		}
	}

	protected static void swap(Object[] array, int i, int j) {
		Object temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}

	public static <T extends Comparable<? super T>> boolean isSorted(T[] array) {
		return isSorted(array, INCREASE, null);
	}

	public static <T extends Comparable<? super T>> boolean isSorted(T[] array,
			boolean order) {
		return isSorted(array, order, null);
	}

	public static <T extends Comparable<? super T>> boolean isSorted(T[] array,
			Comparator<T> comparator) {
		return isSorted(array, INCREASE, comparator);
	}

	public static <T extends Comparable<? super T>> boolean isSorted(T[] array,
			boolean order, Comparator<T> comparator) {
		for (int i = 1; i < array.length; i++) {
			if (compare(array[i], array[i - 1], order, comparator)) {
				return false;
			}
		}
		return true;
	}

	public <T extends Comparable<? super T>> void sort(T[] array) {
		sort(array, INCREASE, null);
	}

	public <T extends Comparable<? super T>> void sort(T[] array, boolean order) {
		sort(array, order, null);
	}

	public <T extends Comparable<? super T>> void sort(T[] array,
			Comparator<T> comparator) {
		sort(array, INCREASE, comparator);
	}

	public abstract <T extends Comparable<? super T>> void sort(T[] array,
			boolean order, Comparator<T> comparator);
}

排序基于Decision Tree,算法至少NlogN。

In-place是说sort用的memory不超过 c*logN.

凡是长距离swap的都是unstable的。

HeapSort 对于cash memory的利用很差,特别是大数组的情况。


1. Selection Sort 选择排序:

每次在剩余的元素中选择最小的,和当前待定排序位置的元素交换位置。Unstable, in-place, O(N^2)

public class SelectionSort extends ArraySort {

	@Override
	public <T extends Comparable<? super T>> void sort(T[] array,
			boolean order, Comparator<T> comparator) {
		for (int i = 0; i < array.length - 1; i++) {
			int base = i;
			for (int j = i + 1; j < array.length; j++) {
				if (compare(array[j], array[base], order, comparator)) {
					base = j;
				}
			}
			swap(array, i, base);
		}
	}

}

2. Insertion Sort 插入排序:

每次将当前元素放到已排序队列的合适位置,利用元素交换,自后向前,逐个比较。Stable, in-palce, O(N^2)

public class InsertionSort extends ArraySort {

	@Override
	public <T extends Comparable<? super T>> void sort(T[] array,
			boolean order, Comparator<T> comparator) {
		for (int i = 1; i < array.length; i++) {
			int j = i;
			while (j > 0) {
				if (compare(array[j], array[j - 1], order, comparator)) {
					swap(array, j, j - 1);
					--j;
				} else {
					break;
				}
			}
		}
	}

}

3. Shell Sort:

每次将给定间隔的元素进行插入排序,间隔为3x+1。 Unstable, in-place, O(N^1.5)

public class ShellSort extends ArraySort {

	@Override
	public <T extends Comparable<? super T>> void sort(T[] array,
			boolean order, Comparator<T> comparator) {
		int N = array.length;
		int step = 1;
		while (step < N / 3) {
			step = 3 * step + 1;
		}
		while (step >= 1) {
			for (int i = step; i < N; i++) {
				for (int j = i; j >= step
						&& compare(array[j], array[j - step], order, comparator); j -= step) {
					swap(array, j, j - step);
				}
			}
			step = step / 3;
		}
	}

}


4. Merge Sort  归并排序:

树形结构,依次将两个有序数组合并成一个。Stable, O(NlgN)

O(N) = O(N/2)+O(N/2)+N

Top-down 递归:

public class MergeSort extends ArraySort {

	// Recursive Merge Sort
	@Override
	public <T extends Comparable<? super T>> void sort(T[] array,
			boolean order, Comparator<T> comparator) {
		@SuppressWarnings("unchecked")
		T[] aux = (T[]) new Comparable[array.length];
		sort(array, aux, 0, array.length - 1, order, comparator);
	}

	private static <T extends Comparable<? super T>> void merge(T[] array,
			T[] aux, int start, int mid, int end, boolean order,
			Comparator<T> comparator) {
		int i = start;
		int j = mid + 1;
		int k = start;
		while (true) {
			if (compare(array[j], array[i], order, comparator)) {
				aux[k++] = array[j++];
			} else {
				aux[k++] = array[i++];
			}
			if (i == mid + 1) {
				while (j <= end) {
					aux[k++] = array[j++];
				}
				break;
			}
			if (j == end + 1) {
				while (i <= mid) {
					aux[k++] = array[i++];
				}
				break;
			}
		}
		System.arraycopy(aux, start, array, start, end - start + 1);
	}

	private static <T extends Comparable<? super T>> void sort(T[] array,
			T[] aux, int start, int end, boolean order, Comparator<T> comparator) {
		if (end - start + 1 < 8) {
			insertionSort(array, start, end, order, comparator);
			return;
		}
		int mid = start + ((end - start) >> 1);
		sort(array, aux, start, mid, order, comparator);
		sort(array, aux, mid + 1, end, order, comparator);
		if (!compare(array[mid + 1], array[mid], order, comparator)) {
			return;
		}
		merge(array, aux, start, mid, end, order, comparator);
	}

	private static <T extends Comparable<? super T>> void insertionSort(
			T[] array, int start, int end, boolean order,
			Comparator<T> comparator) {
		for (int i = start; i <= end; i++) {
			for (int j = i; j > 0; j--) {
				if (compare(array[j], array[j - 1], order, comparator)) {
					swap(array, j, j - 1);
				} else {
					break;
				}
			}
		}
	}

}

Divide and Conquer 方法。aux作为辅助数组用于暂存,只作一次声明。less(后,前)来保证stable。每次merge后要将aux拷贝回原array。

优化:

1. 当数组长度小于8时用插入排序。

2. 两段排序后,当第一段最后的元素不大于第二段第一个元素时,不用merge。

Bottom-up merge sort 非递归:

public static <T extends Comparable<? super T>> void sortBU(T[] array, boolean order, Comparator<T> comparator) {
	int N = array.length;
	@SuppressWarnings("unchecked")
	T[] aux = (T[]) new Comparable[array.length];
	for (int size = 1; size < N; size <<= 1) {
		for (int start = 0; start < N - size; start += size << 1) {
			merge(array, aux, start, start + size - 1, Math.min(start + (size << 1) - 1, N - 1), order, comparator);
		}
	}
}

树形结构自下而上,每两个相邻大小为size的数组进行归并。end要注意,最后一个数组大小够不够size。

5. Quick Sort 快排:

每次分割两部分,左边都比分割点小,右边都比分割点大。

普通Quick Sort:

public class QuickSort extends ArraySort {

	/**** Normal Quick Sort ****/
	@Override
	public <T extends Comparable<? super T>> void sort(T[] array, boolean order, Comparator<T> comparator) {
		sort(array, 0, array.length - 1, order, comparator);
	}

	private static <T extends Comparable<? super T>> void sort(T[] array,
			int start, int end, boolean order, Comparator<T> comparator) {
		if (end - start + 1 <= 10) {
			insertionSort(array, start, end, order, comparator);
			return;
		}
		int mid = partition(array, start, end, order, comparator);
		sort(array, start, mid - 1, order, comparator);
		sort(array, mid + 1, end, order, comparator);
	}

	private static <T extends Comparable<? super T>> int partition(T[] array,
			int start, int end, boolean order, Comparator<T> comparator) {
		int i = start;
		int j = end + 1;
		while (true) {
			// array[start] >= array[++i]
			while (compare(array[++i], array[start], order, comparator)) {
				if (i == end) {
					break;
				}
			}
			// array[start] < array[--j]
			while (compare(array[start], array[--j], order, comparator)) {
				if (j == start) {
					break;
				}
			}
			if (i >= j) {
				break;
			}
			swap(array, i, j);
		}
		swap(array, start, j);
		return j;
	}

	private static <T extends Comparable<? super T>> void insertionSort(
			T[] array, int start, int end, boolean order,
			Comparator<T> comparator) {
		for (int i = start; i <= end; i++) {
			for (int j = i; j > 0; j--) {
				if (compare(array[j], array[j - 1], order, comparator)) {
					swap(array, j, j - 1);
				} else {
					break;
				}
			}
		}
	}
}
3-way Quick Sort:
循环中分割点一直移动,与分割点相等的元素会和分割点排在一起。有利于处理duplicate。
public static <T extends Comparable<? super T>> void sort3Way(T[] array,
			boolean order, Comparator<T> comparator) {
	sort3(array, 0, array.length - 1, order, comparator);
}

public static <T extends Comparable<? super T>> void sort3(T[] array,
		int start, int end, boolean order, Comparator<T> comparator) {
	if (end - start + 1 <= 10) {
		insertionSort(array, start, end, order, comparator);
		return;
	}
	int lt = start;
	int gt = end;
	T v = array[start];
	int i = start;
	while (i <= gt) {
		int cmp = COMPARE(array[i], v, comparator);
		if (order == INCREASE) {
			if (cmp < 0) {
				swap(array, lt++, i++);
			} else if (cmp > 0) {
				swap(array, i, gt--);
			} else {
				i++;
			}
		} else {
			if (cmp < 0) {
				swap(array, i, gt--);
			} else if (cmp > 0) {
				swap(array, lt++, i++);
			} else {
				i++;
			}
		}
	}
	sort3(array, start, lt - 1, order, comparator);
	sort3(array, gt + 1, end, order, comparator);
}

6. 堆排序

建立最大堆,然后依次把堆顶元素放到末尾。

public static <T extends Comparable<T>> void sort(T[] array) {
		int tail = array.length - 1;
		// 建立heap
		for (int i = array.length / 2 - 1; i >= 0; i--) {
			percolateDown(array, i, tail);
		}
		// 排序。依次将最大值移除堆放在数组末尾。通过tail控制堆大小
		while(tail > 0) {
			swap(array, 0, tail--);
			percolateDown(array, 0, tail);
		}
	}

	private static <T extends Comparable<T>> void percolateDown(T[] array, int k, int tail) {
		// 初始化max为左child
		int max = k * 2 + 1;
		if (max > tail) {
			return;
		}
		// 如果右child存在,且大,则max为右child。
		if (max + 1 <= tail && array[max + 1].compareTo(array[max]) > 0) {
			max = max + 1;
		}
		if (array[k].compareTo(array[max]) < 0) {
			swap(array, k, max);
			k = max;
			percolateDown(array, k, tail);
		}
	}

	private static <T> void swap(T[] array, int i, int j) {
		T temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}

Shuffle 打乱:

定义接口:

public interface MyShuffle {
	public <T> void shuffle(T[] array);
}

1. Sort Shuffle 排序打乱:

将每个元素给定一个随机值,将值排序,则元素被打乱

public class SortShuffle implements MyShuffle {
	@Override
	public <T> void shuffle(T[] array) {
		int N = array.length;
		HashMap<Double, T> map = new HashMap<Double, T>();
		double[] val = new double[N];
		for (int i = 0; i < N; i++) {
			val[i] = Math.random() + Math.random();
			map.put(val[i], array[i]);
		}
		Arrays.sort(val);
		for (int i = 0; i < N; i++) {
			array[i] = map.get(val[i]);
		}
	}
}


2. Knuth Shuffle 逐步打乱:

每次当前元素和前面(含自身)的元素随机交换。

public class KnuthShuffle implements MyShuffle {
	public static <T> void swap(T[] array, int i, int j) {
		T temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}
	
	@Override
	public <T> void shuffle(T[] array) {
		int N = array.length;
		Random rand = new Random();
		for (int i = 1; i < N; i++) {
			swap(array, i, rand.nextInt(i + 1));
		}
	}
}

Select 选择:

在数组中选择大小为第k的数字。

定义接口:

public interface MySelect {
	// Check if a < b
	public default <T extends Comparable> boolean less(T a, T b) {
		// public default boolean less(Comparable a, Comparable b)
		return a.compareTo(b) < 0;
	}

	public default <T> boolean less(T a, T b, Comparator<T> comparator) {
		return comparator.compare(a, b) == -1;
	}

	// Swap i and j in array
	public default <T> void swap(T[] array, int i, int j) {
		T temp = array[i];
		array[i] = array[j];
		array[j] = temp;
	}

	// Sort method
	public <T> Comparable<T> select(Comparable<T>[] array, int k);

	public <T> T select(T[] array, int k, Comparator<T> comparator);

}

1. Quick Select 快速选择:

基于Quick Select 快排。
public class QuickSelect implements MySelect {
	@Override
	public <T> Comparable<T> select(Comparable<T>[] array, int k) {
		int start = 0;
		int end = array.length - 1;
		while (start < end) {
			int mid = partition(array, start, end);
			if (mid < k) {
				start = mid + 1;
			} else if (mid > k) {
				end = mid - 1;
			} else {
				return array[k];
			}
		}
		return array[k];
	}

	@Override
	public <T> T select(T[] array, int k, Comparator<T> comparator) {
		int start = 0;
		int end = array.length - 1;
		while (start < end) {
			int mid = partition(array, start, end, comparator);
			if (mid < k) {
				start = mid + 1;
			} else if (mid > k) {
				end = mid - 1;
			} else {
				return array[k];
			}
		}
		return array[k];
	}

	private <T> int partition(Comparable<T>[] array, int start, int end) {
		int i = start;
		int j = end + 1;
		while (true) {
			// array[start] >= array[++i]
			while (less(array[++i], array[start])) {
				if (i == end) {
					break;
				}
			}
			// array[start] < array[--j]
			while (less(array[start], array[--j])) {
				if (j == start) {
					break;
				}
			}
			if (i >= j) {
				break;
			}
			swap(array, i, j);
		}
		swap(array, start, j);
		return j;
	}

	private <T> int partition(T[] array, int start, int end,
			Comparator<T> comparator) {
		int i = start;
		int j = end + 1;
		while (true) {
			// array[start] >= array[++i]
			while (less(array[++i], array[start], comparator)) {
				if (i == end) {
					break;
				}
			}
			// array[start] < array[--j]
			while (less(array[start], array[--j], comparator)) {
				if (j == start) {
					break;
				}
			}
			if (i >= j) {
				break;
			}
			swap(array, i, j);
		}
		swap(array, start, j);
		return j;
	}
}



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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值