快速排序
快排利用的是分治思想。如果要排序陣列中下標從 p 到 r 之間的一組資料,選擇p 到 r 之間的任意乙個資料作為分割槽點pivot。
遍歷 p 到 r 之間的資料,將小於pivot的放到左邊,將大於pivot的放到右邊,將pivot放到中間。經過這一步驟後陣列 p 到 r 之間的資料就被分為了三個部分。陣列 p 到 r 之間的資料就被分成了三個部分,前面 p
到 q-1 之間都是小於 pivot 的,中間是 pivot,後面的 q+1 到 r 之間是大於 pivot 的。再根據分治、遞迴的處理思想,可以用遞迴排序下標從p 到 q-1之間的資料和下標從q+1到 r 之間的資料,直到區間縮小為 1,就說明所有資料都有序了。
用遞推公式將上面的過程寫出來:
遞推公式:
quicksort
(p…r)
=quicksort
(p…q-1)
+quicksort
(q+1
, r)
終止條件:
p >= r
實現方式
方法1: horea 法:
讓 p 從前往後找,找比基準值大的元素,找到就停止
讓 q 從後往前找,找比基準值小的元素,找到後停止
將 p 和 q 標記的元素進行交換(為了讓前半部分小於後半部分,p 指的是小的)
將基準值和 p 位置的資料進行交換
返回 p
分割的時間複雜度:o(n)
quicksort
(int
arr,
int n)
// 快速排序遞迴函式,p r為下標
quick_sort_c
(int
arr,
int p,
int r)
關於獲取分割槽的方法,關鍵在於資料怎麼劃分,取哪個作為基準值
public
intgetindexofmiddle
(int
arr,
int p,
int q)
else
if(arr[pivot]
> arr[q-1]
)else
}else
else
if(arr[pivot]
< arr[q-1]
)else
}}
找到基準之後分割槽方法的寫法
方法2.挖坑法:
其實基本思路和 hoare 法一致,但是有乙個特點是不再進行數的交換,而是進行賦值 (挖坑+填坑)
p 從前往後找,q 從後往前找,將 q 用key儲存,並認為 q 是坑,只要 q 找到大於 key 的,就把 p 對應得元素覆蓋到 q,此時 p 成為新的坑,然後 q 往前走找比key小的,找到後填 p 這個坑,直到兩個相遇後把key賦給 p 或 q 中任何乙個
分割的時間複雜度:o(n)
分割槽函式的寫法:
private
static
intpartition
(int
array,
int left,
int right)
array[i]
= array[j]
;while
(i < j && array[i]
<= pivot)
array[j]
= array[i];}
array[i]
= pivot;
return i;
}
方法3.前後索引
取基準值,可以取最後的
cur指向當前元素(left)的位置,prev指向cur的前面(prev = cur-1)
// 分割槽函式寫法
private
static
intpartition
(int
array,
int left,
int right)
}swap
(array,d-
1,left)
;return d-1;
}
horea法**實現
public
class
quicksort
// 快速排序遞迴函式,p,r為下標
private
static
void
quicksortinternally
(int
arr,
int p,
int r)
int q =
paitition
(arr,p,r)
;// 獲取分割槽點
quicksortinternally
(arr,p,q-1)
;quicksortinternally
(arr,q+
1,r);}
private
static
intpartition
(int
arr,
int p,
int r)
else}}
int tmp = arr[i]
; arr[i]
= arr[r]
; arr[r]
= tmp;
system.out.
println
("i="
+ i)
;return i;
}}
效能分析
快速排序是穩定的演算法嗎?
不穩定,因為分割槽的過程涉及交換操作,如果陣列中有兩個相同的元素,比如序列 6,8,7,6,3,5,9,4,在經過第一次分割槽操作之後,兩個 6 的相對先後順序就會改變。所以,快速排序並不是乙個穩定的排序演算法。
空間複雜度是多少?
可以原地實現,所以是 o(1)
快排的時間複雜度?
每次選擇的pivot都很合適,基準值左右兩部分的值比較均勻,時間複雜度 o(nlogn)
分割槽極不平衡:可以用遞迴樹來分析,會退化到 o(n^2)
應用場景:和堆排序一樣適合對大規模資料、或者隨機數排序。
**對於挖坑法 和 hoare 的簡單小結 **
挖坑法從大到小排序:定義兩個變數 l 和 h 分別指向第乙個和最後乙個數,假設我們選擇第乙個數為坑,用 part 將這個數儲存,從 h 往前找大於 part 的數填坑,填完一次後 h 變成下乙個要填的坑,從 l 往後找小於 part 的數填 h 的坑,此時 l 又成了坑…整個過程記住,h 和 l 誰在做 ++ 或者 – 操作的那個數不變,停下的那一刻另外乙個指標的數被賦值(填坑)。(簡記,敵動我不動,敵不動我就變跟它一樣)。
hoare法從大到小排序:定義兩個變數 p 和 q 分別指向第乙個和最後乙個數,假設選擇第乙個數為分割槽點,q 從當前數往前找小於 arr[0] 的,找到後停止,p從 arr[1] 開始找大於 arr[0]
的,找到後 p 和 q 的數交換,直到 p 和 q 相遇,其中乙個數再和 arr[0] 交換。(p 和 q 遍歷過的地方都是滿足條件的)。
快速排序時間複雜度分析
為了分析快速排序的時間複雜度,請先看下面的主定理 主定理 t n at n b f n 其中 a 1 and b 1 是常量 並且 f n 是乙個漸近正函式,為了使用這個主定理,您需要考慮下列三種情況 快速排序的每一次劃分把乙個 問題分解成兩個子問題,其中的關係可以用下式表示 t n 2t n 2 ...
基於比較氣泡排序 時間複雜度O n 2
只操作相鄰的兩個資料,每次冒泡操作都會對相鄰的兩個元素進行比較,看是否滿足大小關係要求,如果不滿足讓它兩互換。一次冒泡會讓至少乙個元素移動到它應該在的位置,重複 n 次,就完成了 n 個資料的排序工作。eg 對於一組資料 4 5 6 3 2 1第一次冒泡的過程 經過了 5 次比較,此時 3 已經在正...
基於比較的插入排序 時間複雜度O n 2
直接插入排序 insert sort 將陣列中的資料分為兩個區域,已排序區間和未排序區間。初始已排序區間只有乙個元素,就是陣列的第乙個元素。插入演算法的核心思想就是取未排序區間中的元素,在已排序區間中從後往前找到最合適的位置將其插入,並保證已排序區間資料一直有序,重複這個過程,直到未排序區間中元素未...