1.前言:
在了解堆排序的过程时,首先要知道二叉树在列表中时怎么存储的,因为堆排序时基于完全二叉树的算法。
那么完全二叉树的父节点和子节点在列表中时什么关系呢
1.父节点找左节点的编号下标:i[子] = 2i[父] + 1
2.父节点找右节点的编号小标:i[子] = 2i[父] + 2
3.子节点找父节点:i[父亲] = (i[子] -1) // 2
3.用列表来存储二叉树,顺序从上到下,从左到右
2.堆排序中还要涉及到一个十分总要的算法,向下调整
1.思想:当根节点的左右子树都是堆的,可以通过一次向下的调整来将其变成一个堆
2.代码:
def shif(li, first, finaly):
'''
向下调整函数
:param li: 列表
:param first: 指向的是跟节点的小标
:param finaly: 指向最后一个节点的下标
:return:
'''
i = first #i先指向根节点
j = i * 2 +1 #j 先指向左节点
count = li[first] # 用count存储待调整数的值
while j <= finaly: #当j大于最后一个元素的小标时,退出循环
if j + 1 <= finaly and li[j + 1] > li[j]: #比较左右节点的大小,如果右节点大于左节点,则j指向右节点,同时要防止有右节点存在
j = j + 1 #j指向右节点
if li[j] > count: #比较子节点是否大于根节点
li[i] = li[j] #如果大于,子节点上去
i = j #i指向已经空的位置
j = 2 * i + 1 #j再次指向已经空的位置的左子节点
else:
li[i] = count #如果比他的子节点大则放到i这个位置
else:
li[i] = count #这里时说如果j已经超过了最后一个节点,那么count就放到了叶节点
3.那么堆排序的算法时啥呢:
1.建立堆:(农村包围城市)
1.1先看最后一个非叶子节点,先调整它
1.2然后看第二个非叶子几点,进行调整
1.3依次到的倒数第三层的时候,从最后一个节点进行调整,同时结合向下调整
1.4然后依次如此到根节点
2.得到堆顶元素为最大元素
3.去掉堆顶,将堆最后一个元素放到堆顶,此时有通过一个向下调整将它变成一个新的堆
4.堆顶有成为了这个新堆的最大元素
5.重复步骤3,直到堆变空
4.堆排序的实现代码
def shif(li, first, finaly):
'''
向下调整函数
:param li: 列表
:param first: 指向的是跟节点的小标
:param finaly: 指向最后一个节点的下标
:return:
'''
i = first #i先指向根节点
j = i * 2 +1 #j 先指向左节点
count = li[first] # 用count存储待调整数的值
while j <= finaly: #当j大于最后一个元素的小标时,退出循环
if j + 1 <= finaly and li[j + 1] > li[j]: #比较左右节点的大小,如果右节点大于左节点,则j指向右节点,同时要防止有右节点存在
j = j + 1 #j指向右节点
if li[j] > count: #比较子节点是否大于根节点
li[i] = li[j] #如果大于,子节点上去
i = j #i指向已经空的位置
j = 2 * i + 1 #j再次指向已经空的位置的左子节点
else:
li[i] = count #如果比他的子节点大则放到i这个位置
else:
li[i] = count #这里时说如果j已经超过了最后一个节点,那么count就放到了叶节点
def heap_sort(li):
#先建立一个堆
for i in range(((len(li)-1)-1)//2, -1, -1):
shif(li, i, len(li)-1)
#键堆完成
#开始排序
for i in range(len(li) - 1, -1, -1): #i表示堆的最后一个元素
li[i], li[0] = li[0], li[i] #最后一个元素和第一个元素交换位置
shif(li, 0, i-1) #i-1 表示的是新的finaly