堆:分為大根堆和小根堆
大根堆:一棵完全二叉樹,滿足任意一節點都比其孩子節點大。
小根堆:一棵完全二叉樹,滿足任意一節點都比其孩子節點小。
堆排序流程:
構造堆得到堆頂元素,為最大元素
去掉堆頂,將堆的最後乙個元素放到堆頂,然後調整重新使堆有序
堆頂元素為第二大的元素
重複第三步直到堆變空
例如以[4, 5, 3, 6, 1, 2 ]為例:
準備知識:
在以順序儲存的完全二叉樹中,父子節點的關係(下標):
父節點和左孩子:左孩子下標 = 父節點下標 * 2 + 1
父節點和右孩子:右孩子下標 = 父節點下標 * 2 + 2
子節點和父節點: 父節點下標 = (子節點下標 - 1) // 2
最後乙個非葉子節點:n // 2 -1
def sift(nums, low, high):
"""調整堆,使堆有序
:param nums: list
:param low: 根節點
:param high: 尾節點(樹的最後乙個)
:return:
"""temp = nums[low]
i = low
j = 2 * i + 1
while j <= high: # 當前i位置為葉子節點, j超過high了
# 找更大的子節點
if j + 1 <= high and nums[j+1] > nums[j]: #
j = j + 1
if temp < nums[j]:
nums[i] = nums[j]
i = j
j = 2 * i + 1
else: # temp 大於兩個子節點
break
nums[i] = temp
def heap_sort(nums):
# 建堆
l = len(nums)
for i in range(l//2-1, -1, -1):
# i是建堆時要調整的子樹的根節點下標
sift(nums, i, l-1)
for i in range(l - 1, -1, -1):
# 當前的high值
nums[i], nums[0] = nums[0], nums[i]
sift(nums, 0, i-1)
python內建模組heapq幫我們實現了堆排序,內建函式用的是小根堆,上面的**是大根堆,差別不大,heapq模組主要包括三個函式:
heapify(list) 建小根堆 把傳入的list變成小根堆
import heapq
nums = [3, 2, 1, 0, 6]
heapq.heapify(nums)
print(nums)
# [0, 2, 1, 3, 6]
print(nums)
# [0, 2, 1, 3, 6, 4]
# 0# 1
# 2
排序演算法 堆排序
1 什麼是堆 首先它是一顆完全二叉樹,並且父結點的值大於子節點的值 最大堆 或父結點的值小於子結點的值 最小堆 小根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最小者的堆稱為小根堆,又稱最小堆。大根堆 根結點 亦稱為堆頂 的關鍵字是堆裡所有結點關鍵字中最大者,稱為大根堆,又稱最大堆。2 堆...
排序演算法 堆排序
花了一晚上時間研究堆排序,這個排序困擾了哥很久,終於搞清楚了。一 堆的定義 1.父結點的鍵值總是大於或等於 小於或等於 任何乙個子節點的鍵值 2 每個結點的左子樹和右子樹都是乙個二叉堆 都是最大堆或最小堆 二 已知結點 i 則它的子結點 為2 i 1 與 2 i 2 父節點為 i 1 2 三 堆排序...
排序演算法 堆排序
由於不經常使用,之前學習看過的演算法都給忘了。現在把他們寫下來,記錄下來,以方便以後查閱。本篇文章的 即為堆排序的 主函式中是對輸入檔案中的序列進行排序,並將結果輸出到乙個檔案中。這是一種形式類似於google codejam的測試方法。include include using namespace...