# 堆的向下调整性质
# 当根节点的左右子树都是堆时,可以通过一次向下的调整来将其变换成一个堆
def sift(li, low, high): # low是根节点所在位置的下标,high是要调整的树的最后一个元素的下标(用于判断是否结束调整)
tmp = li[low] # 根节点的值存起来
i = low # 根节点下标
j = 2 * i + 1 # 根节点左孩子下标
while j <= high: # 判断j是否存在,不存在说明可以结束调整了
if j + 1 <= high and li[j+1] > li[j]: # 如果右孩子存在并且比左孩子大
j += 1 # j指向右孩子
if li[j] > tmp: # 如果孩子的值比父亲的大,需要进行调整,否则可以结束调整
li[i] = li[j]
i = j
j = 2 * i + 1
else:
break
li[i] = tmp # 调整结束,将tmp的值放到调整后的位置
def heap_sort(li):
# 1. 建堆
n = len(li)
for i in range(n//2-1, -1, -1): # i表示遍历的low, n//2-1是最后一个非叶子节点的下标
sift(li, i, n-1)
# 2. 挨个出数
for i in range(n-1, 0, -1): # i表示逻辑上当前堆的high
li[i], li[0] = li[0], li[i]
sift(li, 0, i-1)
# 最后在出数的时候为了节省空间,我们把出的数放在队尾,i前面的是逻辑上的堆,后面是有序区