快速排序使用分治法(Divide and conquer)策略來把一個序列(list)分爲較小和較大的2個子序列,而後遞歸地排序兩個子序列。java
快排的核心思想是:將要排序的序列(假設下標是從start到end)中選任意一個數據做爲pivot(分區點,也叫基準點),而後遍歷數據,將小於pivot 的數據放在pivot的前面,大於等於 pivot 的數據放在pivot的後面。以後遞歸的將兩個子序列排序。算法
過程以下。數組
這裏咱們給出的是原地排序的實現,也就是算法的執行過程當中不須要額外的空間。ide
public class Quick { // 快速排序,a是數組,n表示數組的大小 public static void quickSort(int[] a, int n) { quickSortInternally(a, 0, n - 1); } // 快速排序遞歸函數 private static void quickSortInternally(int[] a, int start, int end) { if (start >= end) { return; } int q = partition(a, start, end); // 獲取分區點 quickSortInternally(a, start, q - 1); quickSortInternally(a, q + 1, end); } }
上面的這個是遞歸實現的,能夠看出跟歸併排序的代碼有點類似,這裏最主要的就是分區點的獲取。函數
private static int partition(int[] a, int start, int end) { int pivot = a[end]; int i = start; for (int j = start; j < end; ++j) { if (a[j] < pivot) { if (i == j) { ++i; } else { swap(a, i, j); ++i; } } } swap(a, i, end); return i; } public static void swap(int[] a, int i, int j) { int tmp = a[i]; a[i] = a[j]; a[j] = tmp; }
在這裏咱們的分區點都是選擇須要排列的數組的最後一個節點。下面有第一個分區點的獲取步驟的演示,能夠看看。ui
能夠看出 i 始終指向的是數組中第一個值大於分區點的節點,j 則是遍歷數組,尋找值小於分區點的節點,而後與i指向的節點交換位置,以後i++,這樣當j遍歷一遍數組後i左邊的都是值小於分區點的,i右邊都是值大於等於分區點,最後i與分區點交換位置。這樣第一遍遍歷就完成了。code
快排是一種原地、不穩定的算法,他的時間複雜度是 O(nlogn),相比較於歸併排序,快排具備空間的優點,可是他的時間複雜度並不如歸併排序那麼穩定,當須要排列的數組近乎有序時,咱們仍選擇最後一個元素做爲分區點的話,快排的時間複雜度就變成了O(n2)了,blog