快速排序比選擇排序要快得多,采用分而治之的思想,具體實現是用遞歸。
1. 基線條件
數組為空或只包含一個元素
2. 遞歸條件
將數組分解,直到滿足基線條件
3. 工作原理
- 先從數組中選擇一個元素,這個元素我們稱之為基准值(pivot)。
- 找出比基准值小的值放在基准值左邊以及比基准值大的值放在基准值右邊。
- 遞歸左邊和右邊的元組,直到都滿足基線條件后,從棧最高層開始返回。
4. 代碼實現
1 def quicksort(array): 2 if len(array) < 2: 3 return array 4 pivot = array[0] 5 6 lesser = [item for item in array[1:] if item <= pivot] 7 greater = [item for item in array[1:] if item > pivot] 8 9 return quicksort(lesser) + [pivot] + quicksort(greater) 10 11 print(quicksort([5,10,23,222,3,0,12,412,4]))
5. 合並排序和選擇排序
這里要說一下合並排序,運行時間為O(n log n)。而快速排序在最糟糕的情況下的運行時間是O(n 2 ),與選擇排序一樣。
但是我們還是要用快速排序,因為快速排序的平均時間是O(n log n)。而合並序有一個常量,等於每次計算都會加上一個常量,所以實際上快速排序速度更快,前提這兩種算法的大O運行時間差不多。如果是兩種算法的大O運行時間不同,這樣常量將無關緊要。比如二分查找和簡單查找。
6.快速排序的平均情況和最糟情況
只有每次將第一個元素作為基准值,才會出現最糟糕的情況O(n 2 )。最好的情況O(log n)是每次基准值都是中間值。
當層數為O(log n)(用技術術語說,調用棧的高度為O(log n)),而每層需要的時間為O(n)。因此整個算法需要的時間為O(n) * O(log n) = O(n log n)。這就是最佳情況。
在最糟情況下,有O(n)層,因此該算法的運行時間為O(n) * O(n) = O(n 2 )。
7. 復雜版本
def partition(array, left, right): pivot = array[left] while left < right: # 當右邊沒有比pivot小的數,right就一直走到和left重合了,下面這個條件是無法退出循環的,right會一直-1 # while array[right] >= pivot: while left < right and array[right] >= pivot: # 從右邊找比pivot小的數 right -= 1 # 往左走一步 # 如果left已經和right重合了。那么array[left]=array[right]就是自己等於自己 array[left] = array[right] # 找到了比pivot小的數,把當前小的那個數放到最左邊 print(array) # 下面的while的left<right有兩個作用: # 1. 在上一個while循環的時候就可能找到了left = right了 # 2. 在自己while循環的過程中left=right了 while left < right and array[left] <= pivot: # 左邊找比pivot大的數 left += 1 # 因為上面的right一直在往左移動,所以array[right]的位置是往左移動完的位置,並且它的值已經放到最左邊了。 # 或者是和left重合的位置,這樣array[right]=array[left]就是自己等於自己 array[right] = array[left] # 把左邊的值寫到右邊空位上 array[left] = pivot # array[left]和array[right]相等了(也就是在中間了),把原來的值放回中間 return left # left和right都行,最后left和right碰上了 # left和right代表最左邊和最右邊的值 def quick_sort(array, left, right): if left < right: # left = right 就一個元素, left小於right至少有兩個元素 mid = partition(array, left, right) quick_sort(array, left, mid - 1) quick_sort(array, mid + 1, right)