快速排序
快速排序和歸并排序看起來有點像,原理卻大相徑庭。歸并排序是將數據一分為二,如此往復直到不能再分為止,然后再用一個merge函數將分出來的數據按個合并,合并的過程中進行比較。快速排序是為自己隨機選擇一個分區點,將大于和小于該分區點的數放在其兩邊,如此往復直到不能再分為止,快速排序是一邊給自己分區一邊進行比較,是由上至下的。
快速排序代碼實現
"""
快速排序
Author: xingrui
"""
# 快速排序
def quickSort(nums: list, p: int, r: int):
if p >= r:
return
q = partition(nums, p, r)
quickSort(nums, p, q - 1)
quickSort(nums, q + 1, r)
def partition(nums: list, p: int, r: int) -> int:
# 分區點
pivot = nums[r]
i, j = p, p
while j <= r - 1:
if nums[j] < pivot:
nums[i], nums[j] = nums[j], nums[i]
i += 1
j += 1
nums[i], nums[r] = nums[r], nums[i]
return i
if __name__ == "__main__":
nums = [4, 5, 2, 6, 2, 3, 9, 3, 1, 20, 57, 39]
p, r = 0, len(nums) - 1
quickSort(nums, p, r)
print('快速排序,正序排列', nums)
上面的排序方式,選擇分區點每次都是選擇最后一個元素,這種方法有其弊端,當數據本身是比較有序的情況,可能最后一個元素每次都是最大的,那么就會導致改分區點左右兩邊的數據數量極其不平衡,這樣快速排序的時間復雜度就會退化為。
所以,針對快速排序的優化(讓其盡可能分區點選擇的合理),我們可以對分區點選擇做一些操作,比如三數取中法,隨機法。下面一個隨機選擇分區點的快速排序實現:
"""
快速排序
Author: xingrui
"""
import random
# 快速排序
def quickSort(nums: list, p: int, r: int):
if p >= r:
return
q = partition(nums, p, r)
quickSort(nums, p, q - 1)
quickSort(nums, q + 1, r)
# 分區-隨機選點
def partition(nums: list, p: int, r: int) -> int:
# 分區點
randomIndex = random.randint(p, r)
pivot = nums[randomIndex]
nums[r], nums[randomIndex] = pivot, nums[r]
i, j = p, p
while j <= r - 1:
if nums[j] <= pivot:
nums[i], nums[j] = nums[j], nums[i]
i += 1
j += 1
nums[i], nums[r] = nums[r], nums[i]
return i
if __name__ == "__main__":
nums = [4, 5, 2, 6, 2, 3, 9, 3, 1, 20, 57, 39]
p, r = 0, len(nums) - 1
quickSort(nums, p, r)
print('快速排序,正序排列', nums)
分析
快速排序的平均時間復雜度是,在極端情況下會退化為
,而歸并排序的時間復雜度可以穩定在
,然而實際在日常應用中我們見的更多的是快速排序,這是因為歸并排序不是原地排序的算法,如果有1g的數據需要排序,那么可能還需要額外1g的空間來存放臨時數據。
快速排序是原地排序,但不是穩定的排序,在排序過程中大小相同的數字排序過后位置關系可能會發生變化。