分類 ------------ 內部比較排序
數據結構 --------- 數組
最差時間復雜度 ---- 每次選取的基準都是最大(或最小)的元素,導致每次只劃分出了一個分區,需要進行n-1次劃分才能結束遞歸,時間復雜度為O(n^2)
最優時間復雜度 ---- 每次選取的基準都是中位數,這樣每次都均勻的劃分出兩個分區,只需要logn次劃分就能結束遞歸,時間復雜度為O(nlogn)
平均時間復雜度 ---- O(nlogn)
所需輔助空間 ------ O(logn)~O(n),主要是遞歸造成的棧空間的使用(用來保存left和right等局部變量),取決于遞歸樹的深度一般為O(logn),最差為O(n)(基本有序的情況)
穩定性 ---------- 不穩定
原理
???????快速排序使用分治策略(Divide and Conquer)來把一個序列分為兩個子序列。
步驟
- 從序列中挑出一個元素,作為"基準"(pivot).
- 把所有比基準值小的元素放在基準前面,所有比基準值大的元素放在基準的后面(相同的數可以到任一邊),這個稱為分區(partition)操作。
- 對每個分區遞歸地進行步驟1~2,遞歸的結束條件是序列的大小是0或1,這時整體已經被排好序了。
代碼實現
public class QuickSort {
// 劃分函數
int partition(Integer a[], int left, int right)
{
// 選擇最后一個元素作為基準
int pivot = a[right];
// tail為小于基準的子數組最后一個元素的索引
int tail = left - 1;
// 遍歷基準以外的其他元素
for (int i = left; i < right; i++)
{
// 把小于等于基準的元素放到前一個子數組中
if (a[i] <= pivot)
{
tail++;
Tool.exchange(a, tail, i);
}
}
// 最后把基準放到前一個子數組的后邊,剩下的子數組既是大于基準的子數組
Tool.exchange(a, tail + 1, right);
// 該操作很有可能把后面元素的穩定性打亂,所以快速排序是不穩定的排序算法,最終返回基準的索引
return tail + 1;
}
void quicksort(Integer a[], int left, int right)
{
// 基準的索引
int pivot_index;
if (left < right)
{
pivot_index = partition(a, left, right);
quicksort(a, left, pivot_index-1);
quicksort(a, pivot_index+1, right);
}
}
public static void main(String[] args){
Integer[] a = {3,4,1,9,5,2,6,10,20,16,13,11,0};
QuickSort sort = new QuickSort();
sort.quicksort(a,0,a.length-1);
System.out.println("array by QuickSort is " + Tool.arrayToString(a));
}
}
public class Tool {
public static <T> String arrayToString(T[] array){
StringBuilder builder = new StringBuilder("[");
for (int i = 0; i < array.length; i++){
T item = array[i];
builder.append(item + "");
if (i != array.length - 1){
builder.append(",");
}
}
builder.append("]");
return builder.toString();
}
public static <T> void exchange(T[] array, int i, int j){
T temp = array[i];
array[i] = array[j];
array[j] = temp;
}
}
實現結果:
array by QuickSort is [0,1,2,3,4,5,6,9,10,11,13,16,20]