荷兰国旗与快速排序
文章目錄
- 荷蘭國旗問題
- 解決荷蘭國旗問題的思路
- 代碼實現
- 經典快排
- 經典快排的思路
- 代碼實現
- 經典快排存在的缺陷
- 隨機快排
- 隨機快排的思路
- 代碼實現
荷蘭國旗問題
荷蘭國旗問題:給定一個數組arr,和一個數num,請把小于num的數放在數組的左邊,等于num的數放在數組的中間,大于num的數放在數組的右邊。
以arr = [3,8,9,2,5,5],num = 5為例。
解決荷蘭國旗問題的思路
初始化小于邊界less = -1,大于邊界more = len(arr) = 6,當前比較的位置cur = 0。
- 如果當前位置上的數小于 num,交換當前位置上的數與邊界less后一個元素,擴大小于num的范圍,less += 1,cur += 1;
- 如果當前位置上的數大于 num,交換當前位置上的數與邊界more前一個元素,擴大大于num的范圍,more -=1, cur 不變;
- 如果當前位置上的數等于num,less和more均不變,cur += 1。
當cur = more時,停止比較,返回。
第一步:
初始化小于邊界less = -1,大于邊界more = len(arr) = 6,當前比較的位置cur = 0。
第二步:比較cur = 0位置上的數與num
arr[cur] = 3,arr[cur] < num,所以,交換當前位置上的數與邊界less后一個元素(此處,兩者為同一元素3,可不做交換),less += 1, cur += 1。得到:less = 0,cur = 1,more = 6。
第三步:比較cur = 1位置上的數與num
arr[cur] = 8, arr[cur] > num,所以,交換當前位置上的數與邊界more前一個元素,more -= 1,cur不變。得到:less = 0,cur = 1,more = 5。
第四步:比較cur = 1位置上的數與num
arr[cur] = 5, arr[cur] = num, 所以,less不變,more不變,cur += 1。得到:less = 0,cur = 2,more = 5。
第五步:比較cur = 2位置上的數與num
arr[cur] = 9, arr[cur] > num, 所以,交換當前位置上的數與邊界more前一個元素,less不變,more -= 1,cur不變。得到:less = 0,cur = 2,more = 4。
第六步:比較cur = 2位置上的數與num
arr[cur] = 5, arr[cur] = num, 所以,less不變,more不變,cur += 1。得到:less = 0,cur = 3,more = 4。
第七步:比較cur = 3位置上的數與num
arr[cur] = 2, arr[cur] < num, 所以,交換當前位置上的數與邊界less后一個元素,less += 1,cur += 1,more不變。得到:less = 1,cur = 4,more = 4。
第八步:
此時,cur = 4 = more,停止比較,返回數組。實現了小于num的在左邊,大于num的在右邊,等于num的在中間。
代碼實現
def partition(arr, l, r, num):less = l - 1 # 小于邊界more = r + 1 # 大于邊界cur = less + 1 # 當前比較位置while cur < more:if arr[cur] < num:arr[less + 1], arr[cur] = arr[cur], arr[less + 1]less += 1cur += 1elif arr[cur] > num:arr[more - 1], arr[cur] = arr[cur], arr[more - 1]more -= 1else:cur += 1return arrif __name__ == '__main__':a = [3, 8, 9, 2, 5, 5]print(partition(a, 0, len(a) - 1, 5))?
經典快排
經典快排的思路
取數組最后一個元素作為劃分值,將小于劃分值的數放在左邊,大于劃分值的數放在右邊,等于劃分值的數放在中間。然后,對左右兩部分繼續進行上述劃分。直到僅剩一個元素為止。
仍以數組arr = [3, 8, 9, 2, 5, 5]為例:
第一步:
取數組最后一個元素做劃分值,即num = 5。將小于5的放在左邊,大于5的放在右邊,等于5的放中間。屬于arr=[3,8,9,2,5,5],num = 5的荷蘭國旗問題。得到小于邊界less = 1,大于邊界more = 4,如下圖:
第二步:
對于0至less部分,取其最后一個元素做劃分值;相當于是arr = [3,2],num = 2的荷蘭國旗問題。得到小于邊界less = -1,大于邊界more = 1。
對于more至 len([3,2,5,5,9,8]) 部分,仍取其最后一個元素做劃分值;相當于是arr = [9,8],num = 8的荷蘭國旗問題。可得小于邊界less = 3,大于邊界more = 5。如下圖:
第三步:
對于左邊數組[2,3],其數組邊界為left = 0,right = 1
less = -1,對于left到less部分,left大于less,沒有元素,返回;
more = 1,對于more到len([2,3]) = 2,僅有一個元素,返回;
對于右邊數組[8,9],其數組邊界為left = 4,right = 5
less = 3,對于left到less部分,left大于less,沒有元素,返回;
more = 5,對于more到 len([2,3,5,5,8,9]) = 6, 僅有一個元素,返回。
排序完成!
代碼實現
def quick_sort(arr, l, r, num):if l < r: # 當滿足這個條件 一直做下去less, more = partition(arr, l, r, num)quick_sort(arr, l, less, arr[less])quick_sort(arr, more, r, arr[r])return arrdef partition(arr, l, r, num):less = l - 1more = r + 1cur = less + 1while cur < more:if arr[cur] < num:arr[less + 1], arr[cur] = arr[cur], arr[less + 1]less += 1cur += 1elif arr[cur] > num:arr[more - 1], arr[cur] = arr[cur], arr[more - 1]more -= 1else:cur += 1return less, moreif __name__ == '__main__':arr = [3, 8, 9, 2, 5, 5]print(quick_sort(arr, 0, len(arr) - 1, arr[-1]))經典快排存在的缺陷
每次都使用數組最后一個元素做劃分值,復雜度跟數據狀況有很大的關系。
以數組 [1,2,3,4,5,6]為例,每次只排好了一個數,時間復雜度是O(n^2)。
于是,有了隨機快排。
隨機快排
隨機快排的思路
隨機選取數組中的數作為劃分值,將小于劃分值的數放在左邊,大于劃分值的數放在右邊,等于劃分值的數放在中間。然后,對左右兩部分繼續進行上述劃分。直到僅剩一個元素為止。使用隨機,完美地避開了數據狀況問題。
代碼實現
僅需在經典快排的基礎上,添加一個隨機函數即可。
import random, mathdef quick_sort(arr, l, r, num):if l < r: # 隨機選取l到r之間的數,與最后一個位置上的數進行交換# 舍棄浮點數后面的小數位,并取整random_pos = l + int(math.floor(random.random() * (r - l + 1))) arr[r],arr[random_pos] = arr[random_pos],arr[r]less, more = partition(arr, l, r, num)quick_sort(arr, l, less, arr[less])quick_sort(arr, more, r, arr[r])return arrdef partition(arr, l, r, num):less = l - 1more = r + 1cur = less + 1while cur < more:if arr[cur] < num:arr[less + 1], arr[cur] = arr[cur], arr[less + 1]less += 1cur += 1elif arr[cur] > num:arr[more - 1], arr[cur] = arr[cur], arr[more - 1]more -= 1else:cur += 1return less, moreif __name__ == '__main__':arr = [3, 8, 9, 2, 5, 5]print(quick_sort(arr, 0, len(arr) - 1, arr[-1]))總結
- 上一篇: 工程项目经济评价的基本方法
- 下一篇: vrchat模型保存_VRChat简易教