堆排序需要对二叉树有了解
堆排序的堆是一个大根堆的完全二叉树,小根堆是最小的数在堆顶,大根堆是最大的数在堆顶。
二叉树的存储,二叉树是存储在一个列表上的,他的父节点和左孩子节点与右孩子节点的位置关系如下图所示。
对于大根堆二叉树的排序,首先将堆顶的数放到最后,然后将最后面的数3放到堆顶,然后判断3是否大于8和7,小于,比较8和7 的大小,8>7,将8放到堆顶,3放到8的位置;然后比较3和6和5的大小,3小于6和5, 6>5, 将6放到3的位置,3放到6的位置;然后比较3和2和4的大小,4和3交换位置。至此,出最后一个数外,这是一个大根堆二叉树。然后重复前面的操作,将8和倒数第二个位置的数交换位置,循环前面操作,知道只有一个数。
def down_sift(list, low, hight):
"""
low:指向堆顶
hight:指向堆底
"""
tmp = list[low]
i = low
j = 2*i + 1
while(j<=hight):
if(j + 1 <= hight and list[j]<list[j+1]):
j = j + 1
if(list[j]>tmp):
list[i] = list[j]
i = j
j = 2*i + 1
else:
break
list[i] = tmp
二、怎么将一个不是大根堆的二叉树变成大根堆
我们从最后一个非叶子节点开始,也就是下图的3, 调用上面写的函数,low=(n-2)//2,high=n-1,进行一次调整,可以将5和3调换位置,此时的5和3便构成一个局部的大根堆,low向上移动,指向8,调用上面写的函数便可以实现8下面的数构成一个更大的局部大根堆,直至low指向堆顶,整个大根堆便建立完成。最后再调用大根堆排序算法就可以排序。
def heap_sort(list):
n = len(list)
for i in range((n-2)//2,-1,-1):
down_sift(list,i,n-1)
hight = n-1
while(hight >= 0):
tmp = list[0]
list[0] = list[hight]
list[hight] = tmp
down_sift(list,0,hight-1)
hight = hight - 1
return list
完整代码如下
def down_sift(list, low, hight):
"""
low:指向堆顶
hight:指向堆底
"""
tmp = list[low]
i = low
j = 2*i + 1
while(j<=hight):
if(j + 1 <= hight and list[j]<list[j+1]):
j = j + 1
if(list[j]>tmp):
list[i] = list[j]
i = j
j = 2*i + 1
else:
break
list[i] = tmp
def heap_sort(list):
n = len(list)
for i in range((n-2)//2,-1,-1):
down_sift(list,i,n-1)
hight = n-1
while(hight >= 0):
tmp = list[0]
list[0] = list[hight]
list[hight] = tmp
down_sift(list,0,hight-1)
hight = hight - 1
return list
list = [i for i in range(10)]
import random
random.shuffle(list)
print(list)
heap_sort(list)
print(list)