1. 程式人生 > >常用排序演算法-JAVA實現

常用排序演算法-JAVA實現

直接上程式碼。

import java.util.Arrays;

public class Sort {

	public static void main(String[] args) {

		int[] sample = new int[] { 8, 9, 7, 10, 6, 2, 4, 5, 1, 0, 3 };
		insertionSort(sample);

		sample = new int[] { 8, 9, 7, 10, 6, 2, 4, 5, 1, 0, 3 };
		bInsertionSort(sample);

		sample = new int[] { 8, 9, 7, 10, 6, 2, 4, 5, 1, 0, 3 };
		cocktailSort(sample);

		sample = new int[] { 8, 9, 7, 10, 6, 2, 4, 5, 1, 0, 3 };
		shellSort(sample);

		sample = new int[] { 8, 9, 7, 10, 6, 2, 4, 5, 1, 0, 3 };
		selectionSort(sample);

		sample = new int[] { 8, 9, 7, 10, 6, 2, 4, 5, 1, 0, 3 };
		bubbleSort(sample);

		sample = new int[] { 8, 9, 7, 10, 6, 2, 4, 5, 1, 0, 3 };
		quickSort(sample, 0, sample.length - 1);
		System.out.println("快速排序 " + Arrays.toString(sample));

		sample = new int[] { 8, 9, 7, 10, 6, 2, 4, 5, 1, 0, 3 };
		mergeSort(sample, 0, sample.length - 1);
		System.out.println("歸併排序 " + Arrays.toString(sample));

	}

	// 直接插入排序(見縫插針排序),最好n-1,最差n(n-1)/2,複雜度n方
	// 直接插入排序的穩定性取決於換位置條件對等號的處理,不帶等號穩定
	public static void insertionSort(int[] data) {

		int d;
		for (int i = 1; i < data.length; i++) {
			d = data[i];
			for (int j = i; j > 0; j--) {
				if (data[j - 1] > d) {
					data[j] = data[j - 1];
					data[j - 1] = d;
				}
			}
		}
		System.out.println("直接插入排序 " + Arrays.toString(data));

	}

	// 二分插入排序,最好nlog(n),最差n方,複雜度n方
	// 二分插入排序的穩定性取決於尋找中間位置的時要插入值和臨時中間值的等號處理,不帶等號穩定
	public static void bInsertionSort(int[] data) {

		int d, left, right, mid;
		for (int i = 1; i < data.length; i++) {
			d = data[i];
			left = 0;
			right = i - 1;
			while (left <= right) {
				mid = (left + right) / 2;
				if (d < data[mid]) {
					right = mid - 1;
				} else {
					left = mid + 1;
				}
			}
			for (int j = i - 1; j >= left; j--) {
				data[j + 1] = data[j];
			}
			data[left] = d;
		}
		System.out.println("二分插入排序 " + Arrays.toString(data));
	}

	// 希爾排序(遞減增量排序/跳躍直接插入排序),複雜度取決於步長,最最差複雜度為n方,時間複雜度下界為nlogn
	// 不穩定排序,不穩定的很顯然
	public static void shellSort(int[] data) {

		int gap = 5, d;
		while (gap > 0) {

			for (int i = gap; i < data.length; i += gap) {
				d = data[i];
				for (int j = i; j > 0; j -= gap) {
					if (data[j] < data[j - gap]) {
						data[j] = data[j - gap];
						data[j - gap] = d;
					}
				}
			}
			gap--;
		}
		System.out.println("希爾排序 " + Arrays.toString(data));
	}

	// 選擇排序,最好n方,最差n方,時間複雜度為n方
	// 選擇排序是不穩定排序
	public static void selectionSort(int[] data) {

		int min, d = -1;
		for (int i = 0; i < data.length - 1; i++) {
			min = data[i];
			for (int j = i + 1; j < data.length; j++) {
				if (min > data[j]) {
					min = data[j];
					d = j;
				}
			}
			if (d == -1) {
			} else {
				data[d] = data[i];
				data[i] = min;
			}
		}
		System.out.println("選擇排序 " + Arrays.toString(data));
	}

	// 氣泡排序,最好n,最差n方,時間複雜度n方
	// 氣泡排序的穩定性取決於相鄰兩元素比較時對等號的處理,不帶等號穩定
	public static void bubbleSort(int[] data) {

		boolean isBubble = true;
		int tmp;
		while (isBubble) {
			isBubble = false;
			for (int i = 1; i < data.length; i++) {
				if (data[i] < data[i - 1]) {
					isBubble = true;
					tmp = data[i];
					data[i] = data[i - 1];
					data[i - 1] = tmp;
				}
			}
		}
		System.out.println("氣泡排序 " + Arrays.toString(data));
	}

	// 雞尾酒排序(雙向氣泡排序),最好n,最差n方
	// 雞尾酒排序的穩定性取決於相鄰元素比較時對等號的處理,不帶等號穩定
	public static void cocktailSort(int[] data) {

		int head = 0;
		int tail = data.length;
		int tmp;
		boolean isBubble = true;
		for (; head < tail;) {

			isBubble = false;
			for (int i = head + 1; i < tail; i++) {
				if (data[i] < data[i - 1]) {
					isBubble = true;
					tmp = data[i];
					data[i] = data[i - 1];
					data[i - 1] = tmp;
				}
			}
			if (!isBubble)
				break;
			tail--;
			for (int i = tail; i > head; i--) {
				if (data[i] < data[i - 1]) {
					isBubble = true;
					tmp = data[i];
					data[i] = data[i - 1];
					data[i - 1] = tmp;
				}
			}
			if (!isBubble)
				break;
			head++;
		}

		System.out.println("雙向氣泡排序 " + Arrays.toString(data));
	}

	/////////////////////// 重點排序演算法分界線//////////////////////////////

	/**
	 * 快排
	 * 
	 * @param data
	 *            要拍的陣列
	 * @param left
	 *            左限下標
	 * @param right
	 *            右限下標
	 */
	// 快速排序,最好nlogn,最差n方,平均時間複雜度nlogn
	// 不穩定排序
	// 是陣列長度大於10後最理想的排序演算法
	public static void quickSort(int[] data, int left, int right) {

		int i, j, base;
		if (left < right) {

			i = left;
			j = right;
			base = data[i];
			do {
				// 從右向左找到第一個小於基準值的下標
				while (data[j] > base && i < j) {
					j--;
				}
				// 上邊的迴圈停掉可能是找到了一個值比基準值小,也可能是i==j了
				// 如果不是i==j,則接著往下走
				if (i < j) {
					data[i] = data[j];
					i++;
				}
				while (data[i] < base && i < j) {
					i++;
				}
				if (i < j) {
					data[j] = data[i];
					j--;
				}
			} while (i != j);
			data[i] = base;
			quickSort(data, left, i - 1);
			quickSort(data, i + 1, right);
		}

	}

	// 堆排序
	// 先建堆
	// 堆排序:將data[0]與data[n-1]交換,之後對data[0->n-2]作堆調整,重複此過程,直到data[0]與data[1]作交換
	// 堆排序是不穩定排序,時間複雜度(最差、最好、平均)為:nlogn
	// 堆排序的程式碼,呃,應該不會讓你手寫程式碼的

	// 歸併排序,時間複雜度為nlogn,是一種比較高效的排序演算法
	// 歸併排序是一種穩定的排序方式
	public static void mergeSort(int[] data, int first, int last) {

		if (first < last) {
			int mid = (first + last) / 2;
			mergeSort(data, first, mid); // 左邊有序
			mergeSort(data, mid + 1, last); // 右邊有序
			mergeArray(data, first, mid, last); // 合併左右
		}

	}

	// 有空間複雜度消耗
	private static void mergeArray(int[] data, int first, int mid, int last) {
		int[] tmp = new int[last - first + 1];
		int tmp_idx = 0;
		int i = first, j = mid + 1;
		int m = mid, n = last;
		while (i <= m && j <= n) {
			if (data[i] < data[j]) {
				tmp[tmp_idx] = data[i];
				tmp_idx++;
				i++;
			} else {
				tmp[tmp_idx] = data[j];
				tmp_idx++;
				j++;
			}
		}
		while (i <= m) {
			tmp[tmp_idx] = data[i];
			tmp_idx++;
			i++;
		}
		while (j <= n) {
			tmp[tmp_idx] = data[j];
			tmp_idx++;
			j++;
		}
		tmp_idx = 0;
		for (; tmp_idx < tmp.length; tmp_idx++) {
			data[first + tmp_idx] = tmp[tmp_idx];
		}
	}

	// 桶排序(基數排序/箱排序)
	// 計數排序
}