排序算法總結

幾種常見的排序算法
排序一般指對關鍵字的排序,下面的例子都是針對int數值類型舉例,對於Object類似。

相關概念:
1)內排序和外排序
排序過程完全在內存中進行稱內排序,有時數據量大,內存無法全部容納,需要藉助外部存儲設備存取,此種叫外排序

2)穩定排序和不穩定排序
如果待排序序列關鍵字相同,排序後相對順序(前後順序)一定保持不變,則稱此排序算法穩定,否則不穩定

3)排序一般涉及兩個基本操作
比較和移動

//注意自己的包名
package sort;

public class SortAlgorithm {

/*******************常見3種插入排序*******************************************/
	/**
	 * 直接插入排序(*):穩定排序
	 * 平均時間複雜度:O(n^2) ; 空間複雜度:O(1)
	 * 最好時間複雜度:O(n) ; 最差時間複雜度:O(n^2)
	 * 原理簡介:將後面的記錄一個一個插入到前面已有序的序列中
	 */
	public static void directInsert(int[] array) {
		final int len = array.length ;
		int temp, i, j ;
		for(i=1 ; i<len ; i++) {
			j = i-1 ;
			temp = array[i] ;
			while(j>=0 && temp<array[j]) {//比較並移動
				array[j+1] = array[j] ;
				j-- ;
			}
			array[j+1] = temp ;	//插入
		}
	}
	
	/**
	 * 折半插入排序:不穩定排序
	 * 平均時間複雜度:O(n^2) ; 空間複雜度:O(1)
	 * 相對於直接插入排序,只減少了比較次數,並沒有減少移動次數。最好最差時間複雜度一樣
	 * 原理簡介:相比於直接插入排序,對已有序的序列採用二分搜索比較,但失去了穩定性
	 */
	public static void halfInsert(int[] array) {
		final int len = array.length ;
		int temp, i, j, low, high, mid=0 ;
		for(i=1 ; i<len ; i++) {
			temp = array[i] ;
			low = 0 ;
			high = i-1 ;
			while(low<=high) {
				mid = (low+high)/2 ;
				if(temp>array[mid])	//比較
					low = mid+1 ;
				else
					high = mid-1 ;		
			}
			for(j=i-1 ; j>=high+1 ; j--) {	//移動
				array[j+1] = array[j] ;
			}
			array[high+1] = temp ;	//插入
		}
	}
	
	/**
	 * 希爾排序(又叫縮小增量排序,直接插入排序的改進):不穩定排序
	 * 平均時間複雜度:O(n^1.3) ; 平均空間複雜度:O(1)
	 * 原理簡介:以jump爲步長,分組,組內進行排序,最後jump必須爲1
	 */
	public static void shellSort(int[] array) {
		final int len = array.length ;
		int jump = (len-1)/2 ;
		boolean change = true ;
		int t ;
		while(jump > 0) {
			do{
				change = false ;
				for(int i = 0 ; i < len-jump ; i++) {
					if(array[i] > array[i+jump]) {
						t = array[i] ;
						array[i] = array[i+jump] ;
						array[i+jump] = t ;
						change = true ;
					}
				}
			}while(change) ;
			jump = jump/2 ;
		}
	}

	
/*******************常見2種交換排序*******************************************/
	/**
	 * 冒泡排序(*):穩定排序
	 * 平均時間複雜度:O(n^2) ; 空間複雜度:O(1)
	 * 最好時間複雜度:O(n) ; 最差時間複雜度:O(n^2)
	 * 原理簡介:將前面大的數據冒泡到後面
	 */
	public static void bubbleSort(int[] array) {
		int len = array.length ;
		boolean swap = true ;
		while(swap) {
			swap = false ;	//如果沒有交換則已經全部有序
			for(int i=0 ; i<len-1 ; i++) {	//向後冒泡
				if(array[i]>array[i+1]) {	//異或交換兩個整數,浮點數不能這樣用
					array[i] = array[i] ^ array[i+1] ;
					array[i+1] = array[i] ^ array[i+1] ;
					array[i] = array[i] ^ array[i+1] ;
					swap = true ;
				}
			}
			len-- ;	//後面已有序
		}
	}
	
	/**
	 * 快速排序(**):非穩定排序,數值類默認的排序算法
	 * 它是冒泡排序的改進,是目前速度最快的排序方法之一
	 * 平均時間複雜度:O(nlogn) ; 平均空間複雜度:O(logn),因爲有遞歸
	 * 最好時間複雜度:O(nlogn) ; 最差時間複雜度:O(n^2)
	 * 原理簡介:選取基準記錄將序列劃分成兩個子序列,然後遞歸將子序列再劃分成子序列,直到有序
	 */
	public static void quickSort(int[] array, int begin, int end) {
		if(begin<end) {
			int i = partition2(array, begin, end) ;
			quickSort(array, begin, i-1);
			quickSort(array, i+1, end);
		}
	}
	//此方法更好
	private static int partition2(int num[], int begin, int end) {
		int key = num[begin] ;
		while(begin<end) {
			while(num[end]>=key && begin<end) {
				end-- ;
			}
			num[begin] = num[end] ;
			while(num[begin]<=key && begin<end) {
				begin++ ;
			}
			num[end] = num[begin] ;
		}
		num[end] = key ;
		return end ;		
	}
	

/*******************常見2種選擇排序*******************************************/
	/**
	 * 直接選擇排序(*):不穩定排序
	 * 平均時間複雜度:O(n^2) ; 平均空間複雜度:O(1)
	 * 原理簡介:每次選擇剩餘待排序序列的最小值放到前面
	 */
	public static void directSelect(int[] array) {
		final int len = array.length ;
		int temp ;
		int index ;	//記錄最小記錄的數組下標
		for(int i=0 ; i<len ; i++) {
			index = i ;
			for(int j=i+1 ; j<len ; j++) {
				if(array[index] > array[j]) {
					index = j ;
				}
			}
			if(index != i) {	//將最小記錄放到前面
				temp = array[index] ;
				array[index] = array[i] ;
				array[i] = temp ;
			}
		}
	}
	
	/**
	 * 概念:利用了完全二叉樹。當所有非葉子結點的值都大於(小於)其子女節點值,則成爲大根堆(小根堆)
	 * 堆排序(**):不穩定排序
	 * 平均時間複雜度:O(nlogn) ; 空間複雜度:O(1)
	 * 最好時間複雜度:O(nlogn) ; 最差時間複雜度:O(nlogn)
	 * 原理簡介:不斷調整堆,將最大值與末尾交換,找到前K大的數,直至K==N
	 */
	public static void heapSort(int[] array) {
		final int maxIndex = array.length - 1 ;
		int temp ;
		//篩選法建立初始堆
		for(int i=(maxIndex-1)/2 ; i>=0 ; i--) {
			shift(array, i, maxIndex);
		}
		for(int i=maxIndex ; i>=1 ; i--) {	
			temp = array[0] ;
			array[0] = array[i] ;
			array[i] = temp ;
			shift(array, 0, i-1) ;	//調整新堆,最後array[0]最大
		}
	}
	//調整新堆,將num[start]調整到合適的位置,使之成爲大根堆,數組下標基於0
	private static void shift(int[] num, int start, int end) {
		int i = 2*start + 1 ;	//左子節點的數組下標
		int temp = num[start] ;
		while(i <= end) {
			if((i<end) && (num[i]<num[i+1])) {	//比較左右子樹大小
				i++ ;
			}
			if(temp<num[i]) {	//交換,下次循環比較子子樹
				num[start] = num[i] ;
				start = i ;
				i = 2*start + 1 ;
			}
			else {
				break ;
			}
		}
		num[start] = temp ;
	}
	

/*******************二路歸併排序*******************************************/
	/**
	 * 歸併排序(**):穩定排序,Object排序默認使用的排序算法
	 * 平均時間複雜度:O(nlogn) ; 空間複雜度:O(n)
	 * 最好時間複雜度:O(nlogn) ; 最差時間複雜度:O(nlogn)
	 * 原理簡介:將兩個或以上有序表合成新有序表,遞歸實現
	 * @return 返回排序後有序的數組
	 */
	public static int[] mergeSort(int[] array, int low, int high) {
		int mid = (low+high)/2 ;
		if(low<high) {
			mergeSort(array, low, mid);		//使前部分有序,直至一個元素
			mergeSort(array, mid+1, high);	//使後部分有序
			merge(array, low, mid, high);	//合併兩個有序表
		}
		return array ;
		
	}
	//將有序的num[low..mid]和num[mid+1..high]歸併爲有序的num[low,high]
	private static void merge(int[] num, int low, int mid, int high) {
		final int len = high-low+1 ;
		int[] target = new int[len] ;	//藉助臨時空間
		int i = low, j = mid + 1, k = 0 ;
		while(i<=mid && j<=high) {
			if(num[i] <= num[j]) {
				target[k] = num[i++] ;		
			}
			else {
				target[k] = num[j++] ;
			}
			k++ ;
		}
		while(i <= mid) {
			target[k++] = num[i++] ;
		}
		while(j <= high) {
			target[k++] = num[j++] ;
		}
		System.arraycopy(target, 0, num, low, len);	//數組的快速賦值
	}
	
	
	
	public static void main(String[] args) {
		int[] array = ProcessData.getRandIntArray(35) ;
		
//		directInsert(array);
//		halfInsert(array);
//		shellSort(array);
//		bubbleSort(array);
//		quickSort(array, 0, array.length-1);
//		heapSort(array);
		array = mergeSort(array, 0, array.length-1);
		
		//打印數字
		ProcessData.printIntArray(array);
	}
	
	//剩餘問題
	/**
	 * 1、找到數組中前K個最大的數
	 * 2、找到第K個最大的數
	 */

}











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章