快速排序python實現
快速排序
快速排序的實現同樣使用分治法,它的原理是從序列中選擇一個值作為基准值,然后分成比基准值小的序列集合和比基准值小的序列集合和與基准值相等的序列集合。
再將比基准值小的序列集合和比基准值小的序列集合再次進行選擇基准值分割,最后再從下到上每層按照順序合並即可。
如圖:
每次分割都是以序列中的第一個值作為基准值,經過拆分后自然就變成了有順序的
具體算法
def quick_sort(s):
"""快速排序,s為列表"""
# 結束條件
if len(s) < 2:
return
# 從列表取出一個元素作為基准值
p = s[0]
L = [] # 小於
E = [] # 等於
R = [] # 大於
# 把s里的元素放入3個隊列
while len(s) > 0:
if s[-1] < p:
L.append(s.pop())
elif s[-1] == p:
E.append(s.pop())
else:
R.append(s.pop())
quick_sort(L)
quick_sort(R)
s.extend(L)
s.extend(E)
s.extend(R)
if __name__ == '__main__':
s = [1, 7, 3, 5, 4]
quick_sort(s)
print(s)
代碼中實現的是列表的快速排序,類似的也可以實現其他類型序列的排序
時間復雜度
快速排序的時間復雜度有最優情況與最壞情況
最優情況為每一次的基准值都正好為序列的中位數,時間復雜度為nlog(n)
最壞情況為每一次的基准值都恰好是序列的最大值或最小值,時間復雜度為n^2。有意思的是如果每次選第一個數做基准值,但每次這個數又是最小值,那么序列本身就是有序的,但時間復雜度也是最高的
要想
要想優化時間復雜度,基准值的選擇很關鍵,可以使用類似的從序列中選幾個數,再求出他們的中位數做基准值
就地快速排序
上面的快排使用了L,E,R存儲臨時的序列,這樣會占用內存,使用就地快速排序的方式可以在原序列上完成排序,減少了內存的使用
def inplace_quick_sort(s,a,b):
"""列表的就地快速排序,s為列表,a為起始索引,b為終止索引"""
if a >= b:
return
# s[b]作為基准值
p = s[b]
# left和right相當於指向
left = a
right = b-1
# 把除了s[b]d 其他元素按照以s[b]為基准分割
while left <= right:
while left <= right and s[left] < p:
left += 1
while left <= right and p < s[right]:
right -=1
if left <= right:
s[left],s[right] = s[right],s[left]
left,right = left+1,right-1
s[left],s[b] = s[b],s[left]
inplace_quick_sort(s,a,left-1)
inplace_quick_sort(s,left+1,b)
上述代碼是列表的就地快速排序,有部分注釋可以參考,基本原理是:
-
選擇索引b處的值為基准值
-
通過從左到右掃描與從右到左掃描,left是左掃描位置,right是右掃描位置,找到左邊第一個大於基准值的位置與右邊第一個小於基准值的位置
-
然后將這兩個值交換,並將left向右移動,right向左移動,繼續重復進行
-
直到left>right,也就是全部掃描一遍后,將基准值s[b]與最后的left位置交換
-
這樣就完成了分割
-
然后再進行遞歸調用兩個序列