快速排序屬於交換排序,主要步驟是使用基準元素進行比較,把小於基準元素的移動到一邊,大於基準元素的移動到另外一邊。從而把數組分紅兩部分,而後再從這兩部分中選取出基準元素,重複上面的步驟。過程以下:html
紫色:基準元素 綠色:大於基準元素 黃色:小於基準元素java
這種思路叫作分治法。算法
基準元素的選取可隨機選取。下面使用中我會使用第一位的元素做爲基準元素。數組
排序拆分過程以下圖:微信
紫色爲基準元素,(每一輪都從新選取) 綠色爲其餘元素ui
第一輪
spa
第二輪
指針
第三輪
code
如上圖所示: 若元素個數爲n,由於排序過程當中須要和所有元素都比較一遍,因此時間複雜度爲O(n),
而平均狀況下排序輪次須要logn輪,所以快速排序的平均時間複雜度爲O(nlogn)。htm
實現方法有雙邊循環法和單邊循環法
首選選取基準元素(pivot)4,並設置指針left和right,指向數組最左和最右兩個元素,以下:
第一次循環,先從right指針指向的數據(rightData)開始和基準元素比較 若 rightData >= pivot,則right指針向左移動,若 rightData < pivot,則right指針不移動,切換到left指針 left指針指向數據(leftData)與基準元素比較,若 leftData <= pivot,則left指針向右移動,若 leftData > pivot,交換left和right指向的元素。
第一輪指針移動完後,獲得以下結構:
而後 left和right指向的元素進行交換:
第一輪循環結束,從新切換到right指針,重複上述步驟。 第二輪循環後,得:
第三輪循環後,得:
第四輪循環後,得:
判斷到left和right指針指向同一個元素,指針中止移動,使pivot和指針元素進行交換,得:
宣告該輪循環結束,並根據Pivot元素切分爲兩部分,這兩部分的數組再根據上述步驟進行操做。
public class DoubleSort { public static void quickSort(int[] arr, int startIndex, int endIndex) { //遞歸結束條件 if (startIndex >= endIndex) { return; } // 基準元素位置 int pivotIndex = partition(arr, startIndex, endIndex); // 根據基準元素,分紅兩部分進行遞歸排序 quickSort(arr, startIndex, pivotIndex - 1); quickSort(arr, pivotIndex + 1, endIndex); } public static int partition(int[] arr, int startIndex, int endIndex) { // 取第一個元素爲基準元素,也能夠隨機抽取 int pivot = arr[startIndex]; int left = startIndex; int right = endIndex; while (left != right) { // 控制right指針比較並左移 while (left < right && arr[right] >= pivot) { right--; } // 控制left指針比較並右移 while (left < right && arr[left] <= pivot) { left++; } // 交換left和right指針所指向的元素 if (left < right) { int temp = arr[right]; arr[right] = arr[left]; arr[left] = temp; } } arr[startIndex] = arr[left]; arr[left] = pivot; return left; } public static void main(String[] args) { int[] arr = new int[]{4, 7, 6, 5, 3, 2, 8, 1}; quickSort(arr, 0, arr.length - 1); System.out.println(Arrays.toString(arr)); } }
雙邊循環法從數組的兩邊比較並交換元素,而單邊循環法則從數組的一邊遍歷,一直日後比較和交換,實現起來更加的簡單。 過程以下:
首先也是選取基準元素pivot(能夠隨機選擇) 設置一個mark指針指向數組的起始位置,表明小於基準元素的區域邊界(不理解的就把它理解成是等會用來交換元素的就行了)
原始數組以下:
從基準元素下一位開始遍歷數組 若是該元素大於基準元素,繼續往下遍歷 若是該元素小於基準元素,mark指針往右移,由於小於基準元素的區域邊界增大了1(即小於基準元素的多了1位),因此mark就 +1,而且該元素和mark指向元素進行交換。
遍歷到元素3時,由於3 < 4,因此mark右移
而後交換元素
而後就繼續遍歷,根據上面的步驟進行判斷,後面的過程就不寫了。
public class SingleSort { public static void quickSort(int[] arr, int startIndex, int endIndex) { //遞歸結束條件 if (startIndex >= endIndex) { return; } // 基準元素位置 int pivotIndex = partition(arr, startIndex, endIndex); // 根據基準元素,分紅兩部分進行遞歸排序 quickSort(arr, startIndex, pivotIndex - 1); quickSort(arr, pivotIndex + 1, endIndex); } /** * 分治(單邊循環法) * @param arr * @param startIndex * @param endIndex * @return */ public static int partition(int[] arr, int startIndex, int endIndex) { // 取第一個元素爲基準元素,也能夠隨機抽取 int pivot = arr[startIndex]; int mark = startIndex; for(int i = startIndex + 1; i< arr.length; i++) { if (pivot < arr[i]) { continue; } mark ++; int temp = arr[mark]; arr[mark] = arr[i]; arr[i] = temp; } arr[startIndex] = arr[mark]; arr[mark] = pivot; return mark; } public static void main(String[] args) { int[] arr = new int[]{4, 7, 6, 5, 3, 2, 8, 1}; quickSort(arr, 0, arr.length - 1); System.out.println(Arrays.toString(arr)); } }
本人也是初次接觸算法,慢慢的去理解算法的思路和實現過程後,真是爲本身以往寫的算法感到羞愧。該文章也是爲了加深本身對快排算法的印象,若文章有不足之處,懇請各位在下方留言補充。感謝各位的閱讀。Thanks♪(・ω・)ノ。
參考資料:《小灰的算法之旅》 第四章。
我的博客網址: https://colablog.cn/
若是個人文章幫助到您,能夠關注個人微信公衆號,第一時間分享文章給您
原文出處:https://www.cnblogs.com/Johnson-lin/p/11917032.html