1. 程式人生 > >[Java]各種基礎的查詢和排序演算法總結

[Java]各種基礎的查詢和排序演算法總結

查詢方法:
1.順序查詢。
按陣列的順序從前往後一直比較,直到找到目標值返回。
優點:對陣列的結構沒有特定的要求,演算法簡單。
缺點:當陣列個數n較大時,效率低下。
時間複雜度:最大時間複雜度是O(n),最小時間複雜度是O(1),平均時間複雜度是O(n/2).
<span style="white-space:pre">	</span>/**
	 * 順序查詢演算法
	 * 
	 * @param array
	 *            陣列
	 * @param target
	 *            目標
	 * @return 找到,返回下標值;找不到返回0x80000000
	 */
	public int sequentialSearch(int[] array, int target) {
		if (array == null) {
			throw new NullPointerException("the array can't not be null!");
		}
		if (array.length <= 0) {
			throw new IllegalArgumentException("the length of array is illgal!");
		}
		for (int index = 0; index < array.length - 1; index++) {
			if (array[index] == target) {
				return index;
			}
		}
		return Integer.MIN_VALUE;
	}


2.二分查詢:
從陣列的中間開始查詢,若找到目標值則返回;若目標值比中間數小則遞迴查詢前半部分;若目標值比中間數大則遞迴查詢後半部分。
優點:比較次數較少,效率比較高
缺點:只適用於不經常變動有序陣列

時間複雜度:O(log(n))

	/**
	 * 二分查詢演算法 
	 * @param array 有序陣列
	 * @param target 目標數值
	 * @return 找到,返回下標值;找不到返回0x80000000
	 */
	public int binarySearch(int[] array, int target) {
		if (array == null) {
			throw new NullPointerException("the array can't not be null!");
		}
		if (array.length <= 0) {
			throw new IllegalArgumentException("the length of array is illgal!");
		}
		int low = 0;
		int high = array.length - 1;
		while (low <= high) {
			int middle = (low + high) / 2;
			if (target == array[middle]) {
				return middle;
			}
			if (target > array[middle]) {
				low = middle + 1;
			} else {
				high = middle - 1;
			}
		}
		return Integer.MIN_VALUE;
	}




排序方法:
1.插入排序:
將一個數據插入到已經排好序的有序資料中,在有序序列中選出合適的位置插入,從而得到一個新的、個數加一的有序資料。

優點:是穩定的排序方法。
缺點:演算法適用於少量資料的排序

時間複雜度為O(n^2)。
<span style="white-space:pre">	</span>public int[] insertSort(int[] array) {
		if (array == null) {
			throw new NullPointerException("the array can't not be null!");
		}
		if (array.length <= 0) {
			throw new IllegalArgumentException("the length of array is illgal!");
		}
		for (int i = 0; i < array.length - 1; i++) {
			int index = halfFindIndex(array, array[i], i);
			if (index != i) {
				int temp = array[i];
				for (int j = i; j > index; j--) {
					array[j] = array[j - 1];
				}
				array[index] = temp;
			}
		}
		return array;
	}

	private int halfFindIndex(int[] array, int target, int end) {
		int low = 0;
		int high = end;
		int middle = 0;
		while (low <= high) {
			middle = (low + high) / 2;
			if (target < array[middle]) {
				low = middle + 1;
			} else {
				high = middle - 1;
			}
		}
		if (target > array[middle]) {
			middle++;
		}
		return middle;
	}



2.氣泡排序
每次將相鄰的兩個數進行比較,如果想升序,則大數往後,反之亦然。

優點:演算法簡單,穩定演算法
缺點:效率低下的排序方法,在資料規模很小時,可以採用;

時間複雜度:無序O(n^2),有序o(1)
<span style="white-space:pre">	</span>public int[] bubbleSort(int[] array) {
		if (array == null) {
			throw new NullPointerException("the array can't not be null!");
		}
		if (array.length <= 0) {
			throw new IllegalArgumentException("the length of array is illgal!");
		}
		int flag = array.length - 1;
		while (flag > 0) {
			int end = flag;
			flag = 0;
			for (int i = 0; i < end; i++) {
				if (array[i] > array[i + 1]) {
					int temp = array[i + 1];
					array[i + 1] = array[i];
					array[i] = temp;
					flag = i;
				}
			}
		}
		return array;
	}




3.歸併排序
採用分治的思想,通過分割和合並,達到目的

優點:演算法簡單,穩定演算法

平均時間複雜度:O(nlog2n)

空間複雜度:O(n)  (用於儲存有序子序列合併後有序序列)

	/**
	 * 歸併排序
	 * 
	 * @param unSortArray
	 * @return
	 * @throws NullPointerException
	 * @throws IllegalArgumentException
	 */
	public int[] mergerSort(int[] unSortArray) throws NullPointerException,
			IllegalArgumentException {
		if (unSortArray == null) {
			throw new NullPointerException("the array is null!");
		}
		if (unSortArray.length <= 0) {
			throw new IllegalArgumentException("the size of array is illgal!");
		}
		int last = unSortArray.length - 1;
		int[] temp = new int[unSortArray.length];
		return merger(unSortArray, 0, last, temp);
	}

	/**
	 * 遞迴實現歸併排序
	 * 
	 * @param unSortArray
	 *            無序陣列
	 * @param first
	 *            開始下標
	 * @param last
	 *            最後有效下標
	 */
	private int[] merger(int[] unSortArray, int first, int last, int[] temp) {
		if (temp == null) {
			return null;
		}
		if (first < last) {
			int middle = (first + last) / 2;
			// 左邊
			merger(unSortArray, first, middle, temp);
			// 右邊
			merger(unSortArray, middle + 1, last, temp);
			// 排序
			mergerArray(unSortArray, first, middle, last, temp);
		}
		return unSortArray;
	}

	/**
	 * 將兩個有序序列合併成一個有序序列
	 * 
	 * @param array
	 *            一個無序序列
	 * @param first
	 *            開始的座標
	 * @param last
	 *            最後的座標
	 * @param temp
	 *            暫存陣列
	 */
	private void mergerArray(int[] array, int first, int mid, int last,
			int[] temp) {
		int start = first;
		int latterIndex = mid + 1;
		int tempIndex = 0;

		while (start <= mid && latterIndex <= last) {
			// 比較將數放進暫存陣列中
			if (array[start] < array[latterIndex]) {
				temp[tempIndex++] = array[start++];
			} else {
				temp[tempIndex++] = array[latterIndex++];
			}
		}
		while (start <= mid) {
			// 將middle以前的有序序列暫存到陣列中
			temp[tempIndex++] = array[start++];
		}
		while (latterIndex <= last) {
			// 將middle以後的有序序列暫存到陣列中
			temp[tempIndex++] = array[latterIndex++];
		}

		for (int i = 0; i < tempIndex; i++) {
			// 將暫存數組裡的數複製到一開始的無序序列中
			array[first + i] = temp[i];
		}
	}



4.快速排序
1.先從數列中取出一個數作為基準數。


2.分割槽過程,將比這個數大的數全放到它的右邊,小於或等於它的數全放到它的左邊。


3.再對左右區間重複第二步,直到各區間只有一個數。
是不穩定的演算法


快速排序時間複雜度下界為O(nlgn),最壞情況為O(n^2)。在實際應用中,快速排序的平均時間複雜度為O(nlgn)

只要對快速排序做簡單的操作,就能使時間複雜度總是O(nlgn):

1.對排序資料進行打亂;

2.隨機挑選基準數.



額外空間O(log(n))

<span style="white-space:pre">	</span>public int[] quickSort(int[] unSortArray, int left, int right)
			throws NullPointerException, IllegalArgumentException {
		if (unSortArray == null) {
			throw new NullPointerException("the array is null!");
		}
		if (unSortArray.length <= 0) {
			throw new IllegalArgumentException("the size of array is illgal!");
		}
		if (left < right) {
			int start = left;
			int end = right;
			// 選第一個為基準
			int x = unSortArray[start];
			while (start < end) {
				while (start < end && x < unSortArray[end]) {
					// 找到小於基準的數
					end--;
				}
				if (start < end) {
					// 交換位置
					unSortArray[start] = unSortArray[end];
					start++;
				}
				while (start < end && x > unSortArray[start]) {
					// 找到大於基準的數
					start++;
				}
				if (start < end) {
					// 交換位置
					unSortArray[end] = unSortArray[start];
					end--;
				}
			}
			unSortArray[start] = x;
			quickSort(unSortArray, left, start - 1); // 遞迴呼叫
			quickSort(unSortArray, start + 1, right);
		}
		return unSortArray;
	}