Python 堆排序
叶子节点数:
n0=n2+1
n
0
=
n
2
+
1
,下标表示度
平均深度h:
N−−√
N
,N表示节点个数
完全二叉树:1到k-1层,都是满的二叉树,第k层,叶节点集中在左边
i从0开始,
子节点找父节点:
int( (i-1) / 2 )
或(区别在于i=0,上面为0,下面取值为-1;一般都行,不会父节点去找父节点)
(i-1)//2
父节点找子节点:
左节点:2 * i + 1
右节点:2 * i + 2
最大堆:max_heap,节点值 >= 子节点
最小堆:min_heap,节点值 <= 子节点
堆排序:不稳定,时间复杂度O(nlogn),空间复杂度最好O(1)
构建堆
def max_heap(L, i, k):
# k控制当前L的取值范围,配合原地堆排序
# i 表示度=2的节点(相对父节点),
# 初始为最后一个度=2的节点,值(len(L)-1)//2
# 二叉树,最后一个度=2的节点,也就是最后一个节点n的父节点,(n-1)//2
l, r = 2*i+1, 2*i+2
maxN = i # 默认父节点值最大
h = len(L[:k])-1
if l < h and L[maxN] < L[l]:
# l<h, 表示左节点存在;然后和最大值比较
maxN = l
if r <= h and L[maxN] < L[r]:
# r<=h, 表示右节点存在;然后和最大值比较
maxN = r
if maxN != i:
# 表示最大节点不是父节点
# 交换父节点、最大节点的值
L[maxN], L[i] = L[i], L[maxN]
# 因为从下到上建立堆,下面的堆都已经建立好,但现在和父节点交换,
# 可能因为父节点较小,会打破已经建立好的下面的堆
# 不确定交换后得到的左/右节点,和其子节点还能满足最大堆性质
max_heap(L, maxN, k)
def build_heap(L, k):
# k,默认为len(L)长度,用来控制原地堆排序算法的,只构建堆时不需要
# 取度为2的最后一个节点,父节点
# 因为最后一个节点为len(L),所以其父节点为(len(L)-1)//2
# 完全二叉树,也就是最后一个度为2的节点
ii = (len(L[:k])-1)//2
while ii>=0:
# 从最后一个度=2的父节点,到根节点ii=0
max_heap(L, ii, k)
ii -= 1 # 从下到上建立堆
堆排序
def heap_sort(L):
build_heap(L, len(L)) # 建立最大堆
for i in range(len(L)-1, 0 ,-1):
# i初始值为最后一位数值,循环最后取值i=1
# 将第一位数也就是最大值和最后一位交换
L[0], L[i] = L[i], L[0]
# 对L[:i],取不到i,进行构建最大值,
# 然后再次循环交换第一位数和当前最后一位i
build_heap(L, i)