快速排序是一種分治思想,裏面通過將定位一個基準數然後劃分兩個數組,然後再各自對這兩個數組進行相同的算法,一直到一個空數組(開頭和結尾都是同一個下標)
原理
首先通過定位一個基準數,然後通過移動指針將其劃分兩個數組,如果是正序那麼就是比基準數大的放右邊,比它小的放左邊,如果是倒敘,那麼比它大的放左邊,比它小的放右邊。這樣就將一個數組分成了兩個子數組,然後再按照同樣的方法把子數組再分成更小的子數組,直到不能分解爲止。
實現
- 空間複雜度:快速排序是一種原地排序,只需要一個很小的棧作爲輔助空間,空間複雜度爲O(log2n),所以適合在數據集比較大的時候使用。
- 時間複雜度:時間複雜度比較複雜,最好的情況是O(n),最差的情況是O(n2),所以平時說的O(nlogn),爲其平均時間複雜度。最差情況:[7,6,5,4,3,2,1]相當於冒泡
# 快排算法
def quick_sort(start, end, arr):
# 如果start和end相同了就說明已經遞歸完整個數組了
if not start < end:
return
"""
取第一個數爲基準數,然後將比其小的放左邊比它大的放右邊,由此可以劃分兩個數組。
然後將這兩個數組再次快排,就實現了整個快排算法,這也是一種分治思想
"""
baseValue = arr[start]
# 用來標記比基準數大的偏移量(從左往右)
little = start
# 用來標記比基準數小的偏移量(從右往左)
big = end
# 只要big和little沒有碰頭就說明沒有遍歷完整個數組
while little < big:
"""
只要數組未便利完,並且當前數組右側比左側大可以說明該右側數組是存放比基準數大的數組。
如果出現比基準數小的,則跳出循環並且將該值覆蓋到arr[little]的位置,如果是第一次則相當於將基數覆蓋
"""
while little < big and arr[big] > baseValue:
big -= 1
# 跳出循環說明該arr[big]的值比arr[little]的值小,所以進行覆蓋
arr[little] = arr[big]
"""
只要數組未便利完,並且當前數組左側比右側大可以說明該左側數組是存放比基準數小的數組。
如果出現比基準數大的,則跳出循環並且將該值覆蓋到arr[big]的位置
"""
while little < big and arr[little] <= baseValue:
little += 1
# 跳出循環說明該arr[little]的值比arr[big]的值大,所以進行覆蓋
arr[big] = arr[little]
# 當這個while跳出來之後相當於little和big碰頭了,所以可以理解爲這個位置是類似於中位數的一個存在
arr[little] = baseValue
"""
這時候以中位數爲標準可以知道左側存放的都是比其小的,右側是放比它大的。
然後通過同樣的算法可以獲取一個順序的數組
"""
# 中位數左側數組
quick_sort(start, little - 1, arr)
# 中位數右側數組
quick_sort(little + 1, end, arr)
if __name__ == '__main__':
arr = [5, 4, 7, 2, 1, 5, 3, 2, 9, 6, 7]
quick_sort(0, len(arr) - 1, arr)
print(arr)
進階版:
# 快排算法
def quick_sort(start, end, arr, sort):
# 如果start>=end了就說明已經遞歸完整個數組了
if not start < end:
return
"""
取第一個數爲基準數,然後將比其小的放左邊比它大的放右邊,由此可以劃分兩個數組。
然後將這兩個數組再次快排,就實現了整個快排算法,這也是一種分治思想
"""
baseValue = arr[start]
# 用來標記比基準數大的偏移量(從左往右)
little = start
# 用來標記比基準數小的偏移量(從右往左)
big = end
if sort == "<":
# 只要big和little沒有碰頭就說明沒有遍歷完整個數組
while little < big:
"""
只要數組未便利完,並且當前數組右側比左側大可以說明該右側數組是存放比基準數大的數組。
如果出現比基準數小的,則跳出循環並且將該值覆蓋到arr[little]的位置,如果是第一次則相當於將基數覆蓋
"""
while little < big and arr[big] > baseValue:
big -= 1
# 跳出循環說明該arr[big]的值比arr[little]的值小,所以進行覆蓋
arr[little] = arr[big]
"""
只要數組未便利完,並且當前數組左側比右側大可以說明該左側數組是存放比基準數小的數組。
如果出現比基準數大的,則跳出循環並且將該值覆蓋到arr[big]的位置
"""
while little < big and arr[little] <= baseValue:
little += 1
# 跳出循環說明該arr[little]的值比arr[big]的值大,所以進行覆蓋
arr[big] = arr[little]
else:
# 只要big和little沒有碰頭就說明沒有遍歷完整個數組
while little < big:
"""
原理跟正序便利相同,結果相反而已
"""
while little < big and arr[big] < baseValue:
big -= 1
arr[little] = arr[big]
"""
原理跟正序便利相同,結果相反而已
"""
while little < big and arr[little] >= baseValue:
little += 1
arr[big] = arr[little]
# 當這個while跳出來之後相當於little和big碰頭了,所以可以理解爲這個位置是類似於中位數的一個存在
arr[little] = baseValue
"""
這時候以中位數爲標準可以知道左側存放的都是比其小的,右側是放比它大的。
然後通過同樣的算法可以獲取一個順序的數組
"""
# 中位數左側數組
quick_sort(start, little - 1, arr, sort)
# 中位數右側數組
quick_sort(little + 1, end, arr, sort)
if __name__ == '__main__':
arr = [5, 4, 7, 2, 1, 5, 3, 2, 9, 6, 7]
quick_sort(0, len(arr) - 1, arr, "<")
print(arr)
arr = [5, 4, 7, 2, 1, 5, 3, 2, 9, 6, 7]
quick_sort(0, len(arr) - 1, arr, ">")
print(arr)