排序算法学习笔记--堆排序的Python实现
网上找了很多堆排序的帖子,大部分代码都没有注释,自己理解后写了带注释的。
堆排序的原理:
构造大顶堆或小顶堆,使得根节点,即目标数组arr[0]为最大/最小。交换arr[0]和arr[-1],将最大值/最小值储存到最后一个位置,然后以arr[-1]前面的元素构造大顶堆,重复上述过程。
代码
# 主要分为三部分
def heap_sort(s):
# 第一部分,heapify函数,第一次构造大顶堆,需要从最后一排的非叶子节点的最后一个开始,向上遍历
# 不能由上向下的原因是,需要将可能的大数字从下面搬运到上面
def heapify(s,length,i):
l = i*2+1
r = i*2+2
largest = i
if l < length and s[l] > s[largest]:
largest = l
if r < length and s[r] > s[largest]:
largest = r
if largest != i:
s[i], s[largest] = s[largest],s[i]
heapify(s,length,largest)
# 第二部分,从后向前/从下向上调用heapify初始化大顶堆
length = len(s)
for i in range(length//2-1,-1,-1):
heapify(s,length,i)
# 第三部分,大顶堆就绪,从后向前遍历s,将s[0],即大顶堆根节点和最后的叶子节点对调,并length-=1,使得接下来构造大顶堆时,刚刚对调的最后一位不会被重新排序。并且一定要从上向下构造大顶堆。
for i in range(len(s)-1,0,-1):
s[0],s[i] = s[i],s[0]
length -= 1
heapify(s,length,0)
print(s)
我自己学习堆排序代码时,一直不理解第一次构造大顶堆的时候为什么要从下向上,而第一次构建完成并将首位元素对调后的构造却要从下向上。仔细想想后,是因为一开始的数组是无序的,从上向下的构造会因为当左右节点比根节点小,且比这三个节点更大的节点在更深层节点时,会遍历不到深层节点,导致大值没有被从深层节点换到根节点。例如[3,2,1,4],若从上向下遍历,子树[3,2,1]满足条件,则不会再向下遍历,最大值4没有被换上来。从下向上遍历时,[3,2,1,4]–>[3,4,1,2]–>[4,3,1,2],就可构造大顶堆。而之后构造大顶堆时一定要从上向下,因为最小的数字现在在根节点,最大的数字在根节点的子节点上,若从下向上没办法把最小的数字搬运到叶子节点。