概念
快速排序是一種原地排序,只需要一個很小的棧作爲輔助空間,空間複雜度爲O(logN),所以適合在數據集比較大且無序的時候使用。實現方法有經典快排和雙指針快排,本文介紹的是雙指針快排的實現。
【注意】:快排的經典排序實現的partition過程其實就是荷蘭國旗問題,不明白的或者不熟悉的可以先看一下荷蘭國旗算法。本文的實現主要講雙指針法。
荷蘭國旗算法:荷蘭國旗問題&快排&BFPRT算法 - god-jiang的文章 - 知乎
時間複雜度
時間複雜度比較複雜,最好的情況是O(N),最差的時候是O(N^2),所以平時說的O(N*logN)爲其平均時間複雜度。
基本思想
隨機找出一個數,可以隨機取,也可以取固定位置,一般是取第一個或最後一個稱爲基準,然後就是比基準小的放在左邊,比基準大的放到右邊。如何放呢?就是和基準進行交換,這樣交換完左邊都是比基準小的,右邊都是比較基準大的,這樣就將一個數組分成了兩個子數組,然後再按照同樣的方法把子數組再分成更小的子數組,直到不能分解爲止。
操作實現
partition方法中
1.選擇數組中的第一個元素arr[startIndex]作爲軸(pivot)
2.右指針爲right,從最右面的一個元素開始向左尋找第一個小於等於pivot的數值
3.左指針爲left,從最左邊開始尋找第一個比pivot大的數
4.經過2,3兩個步驟後,將會出現以下兩種情況
(1):left和right沒有相遇,此時進行交換,swap(arr,left,right);
(2):left和right相遇,做swap(arr,startIndex,left),然後返回left
5.partition中返回pivot用於分割數組,下一次用於排序的數組被分割爲(startIndex,pivot-1),(pivot+1,endIndex)兩段,進行遞歸操作
過程演示
給定一個原始數組爲:
開始時,我們首先選擇第一個數作爲基準pivot,並且設置兩個指針left和right,指向數組的最左位置和最右位置:
從right位置開始和基準pivot比較,直到right對應的那個數比基準pivot小的時候停下;然後從left位置開始和基準pivot比較,直到left對應的那個數比基準pivot大的時候停下。因爲right對應的1比4小,所以停下不動;left對應的是4沒有大於4,所以向右移動,然後left對應的是7比4大,所以停下不動:
這時交換left和right的位置:
接下來繼續重複剛纔的過程,right向左移動到8比4大,繼續移動到2,比4小,所以停下;然後left向右移動到6比4大,所以停下:
這時交換left和right的位置:
繼續重複上面的過程,right向左移動到3比4小,所以停下;left向右移動到5比4大,所以停下:
這時交換left和right的位置:
right向左移動和left指針重合,這個時候停下:
當left和right重合的時候,我們把pivot位置和left位置進行交換,這個時候就是一趟快排的結果,基準pivot的值是4,它的左邊都比4小,它的右邊都比4大:
然後就通過分治遞歸的方法,分別對左邊和右邊繼續剛纔的過程,直到數組不能再分爲止。
代碼實現
import java.util.Arrays;
/**
* @author god-jiang
* @date 2020/1/12
*/
//時間複雜度O(n*logn),空間複雜度O(n*logn)
public class QuickSort {
public static void quickSort(int[] arr, int startIndex, int endIndex) {
if (startIndex < endIndex) {
//找出基準
int partition = partition(arr, startIndex, endIndex);
//分成兩邊遞歸進行
quickSort(arr, startIndex, partition - 1);
quickSort(arr, partition + 1, endIndex);
}
}
//找基準
private static int partition(int[] arr, int startIndex, int endIndex) {
int pivot = arr[startIndex];
int left = startIndex;
int right = endIndex;
while (left != right) {
while (left < right && arr[right] > pivot) {
right--;
}
while (left < right && arr[left] <= pivot) {
left++;
}
//找到left比基準大,right比基準小,進行交換
if (left < right) {
swap(arr, left, right);
}
}
//第一輪完成,讓left和right重合的位置和基準交換,返回基準的位置
swap(arr, startIndex, left);
return left;
}
//兩數交換
public static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
public static void main(String[] args) {
int[] a = {2, 4, 6, 1, 3, 7, 9, 8, 5};
quickSort(a, 0, a.length - 1);
System.out.println(Arrays.toString(a));
}
}
運行截圖
1、以上就是今天分享的快速排序,時間複雜度爲O(NlogN),空間複雜度爲O(NlogN)
2、快排是不穩定排序,要想做到穩定性是可以的,但是非常難,不需要掌握,有一篇論文叫”01 stable sort”可以做到
3、有一道題目,是奇數放數組左邊,偶數放在數組右邊,還要求原始的相對次序不變,額外空間複雜度爲O(1),碰到這個問題,直接可以懟面試官,根本不可能做出來
PS:因爲博主畫圖實在太醜了,所以去了“程序員小灰”的公衆號copy了他的圖片來講解快排的整個過程。覺得博主寫的還不錯的點點贊,關注走一波,謝謝大家的支持了,我們一起進步吧~~~