堆分为大根堆和小根堆
大根堆是一颗完全二叉树,且根节点大于所有子节点,每棵子树也是大根堆
堆排序要做的就是(1)先把列表构造成一棵二叉树,然后将这棵二叉树调整成大根堆
(2)然后将根节点与最后一个子节点交换,删掉最后一个子节点(并不是真的删掉,只是下次排序不带它)
(3)将剩下的二叉树重新调整成大根堆
重复(2)(3)直到堆为空
关于构造大根堆和调整大根堆的过程可以参考这个神奇的网站
https://visualgo.net/en/heap?slide=1
它可以动态展示大根堆得构造过程,堆排序得过程,,以及添加新节点后重新调整为大根堆的过程,仔细看几遍,对理解堆排序很有帮助,配合代码注释食用更佳
lists = [9, 78, 54, 91, 86, 53, 88, 66, 46, 15]
"""自下而上构造大根堆"""
def create_heap(a):
f = len(a) // 2 - 1
for i in range(f, -1, -1):
"""找到左孩子"""
left_child = 2 * i + 1
"""如果存在右孩子,并且大于左孩子,指针指向右孩子"""
if left_child + 1 < len(a) and a[left_child] < a[left_child + 1]:
left_child = left_child + 1
"""如果较大的孩子比父亲大,则交换"""
if a[left_child] > a[i]:
swap(a, left_child, i)
recreate_heap(a, left_child, len(a))
"""自上而下调整大根堆"""
def recreate_heap(a, parent, end):
left_child = parent*2+1
if left_child > end:
return
if left_child+1 < end and a[left_child] < a[left_child+1]: #len(a) -> end
left_child = left_child+1
if a[left_child] > a[parent]:
swap(a, left_child, parent)
recreate_heap(a, left_child, end) #如果父亲比孩子小,交换完之后,以孩子为节点的子树很可能也需要调整
"""堆排序"""
def heap_sort(a):
"""先构造大根堆"""
create_heap(a)
"""将根节点与第i个节点交换,调整大根堆"""
for i in range(len(a)-1, -1, -1):
swap(a, 0, i)
recreate_heap(a, 0, i-1)
print(a)
"""交换两个数"""
def swap(list, a, b):
temp = list[a]
list[a] = list[b]
list[b] = temp
heap_sort(lists)
print(lists)