排序演算法—快速排序(Quick Sort)
阿新 • • 發佈:2020-11-04
快速排序(Quick Sort)
快速排序的基本思想:通過一趟排序將待排記錄分隔成獨立的兩部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。
1.演算法描述
快速排序使用分治法來把一個串(list)分為兩個子串(sub-lists)。具體演算法描述如下:
- 從數列中挑出一個元素,稱為 “基準”(pivot);
- 重新排序數列,所有元素比基準值小的擺放在基準前面,所有元素比基準值大的擺在基準的後面(相同的數可以到任一邊)。在這個分割槽退出之後,該基準就處於數列的中間位置。這個稱為分割槽(partition)操作;
- 遞迴地(recursive)把小於基準值元素的子數列和大於基準值元素的子數列排序。/
2.具體演算法實現
- 先選擇一個基準(base),一般是陣列最左邊的值,或者是最右邊的值(如果base是左邊,則從右邊開始。)
- 如果j需要從右往左遍歷,如果發現arr[j]<base則停下,i開始從左往右遍歷,發現arr[i]>base停下。
- 交換arr[i]與arr[j]的位置
- 然後j和i繼續尋找,並交換位置
- 當i和j相同時,結束一輪尋找,並將此時的數字與base交換。
- 此時根據base,將陣列分割成兩個部分,其中一部分記錄的關鍵字均比另一部分的關鍵字小,則可分別對這兩部分記錄繼續進行排序,以達到整個序列有序。
3. 演算法分析
快速排序演算法的時間複雜度和各次標準資料元素的值關係很大。如果每次選取的標準元素都能均分兩個子陣列的長度,這樣的快速排序過程是一個完全二叉樹結構。(即每個結點都把當前陣列分成兩個大小相等的陣列結點,n個元素陣列的根結點的分解次數就構成一棵完全二叉樹)。這時分解次數等於完全二叉樹的深度log2n;每次快速排序過程無論把陣列怎樣劃分、全部的比較次數都接近於n-1次,所以最好情況下快速排序演算法的時間複雜度為O(nlog2n):快速排序演算法的最壞情況是資料元素已全部有序,此時資料元素陣列的根結點的分需次數構成一棵二叉退化樹(即單分支二叉樹),一棵二叉退化樹的深度是n,所以最壞情況下快速排序演算法的時間複雜度為O(n2)。般情況下 ,標準元素值的分佈是隨機的,陣列的分郵大數構成模二又樹,這樣的二叉樹的深度接近於log2n, 所以快速排序演算法的平均(或稱期望)時間複雜度為O(nlog2n)
public class quickSort { public static void main(String[] args) { int[] arr=new int[10000]; int n=arr.length; Random random = new Random();//預設構造方法 for(int i=0;i<n;i++) { arr[i]=(int)random.nextInt(100);//在陣列中隨機生成[0,100)的數 } funQuickSort(arr,0,n-1); } public static void funQuickSort(int[] arr,int start,int end ) { if(start>end) { return; } int base=arr[start]; int i=start; int j=end; while (i!=j) { while(arr[j] >= base && i < j) { j--; } while(arr[i] <= base && i < j) { i++; } int temp=arr[i]; arr[i]=arr[j]; arr[j]=temp; } arr[start]=arr[i]; arr[i]=base; funQuickSort(arr,start,i-1); funQuickSort(arr,j+1,end); } }
快速排序前的陣列:2 43 7 46 43 25 26 36 22 35 32 41 26 34 42 29 39 43 4 3 46 4 17 45 36 48 21 16 26 0 39 45
快速排序後的陣列:0 2 3 4 4 7 16 17 21 22 25 26 26 26 29 32 34 35 36 36 39 39 41 42 43 43 43 45 45 46 46 48