刚讲完堆的一系列基本内容,把涉及的知识点整理下,看课本81-88页自行对照复习。
The initial seq is [0, 45, 36, 18, 53, 72, 30, 48, 93, 15, 35]:
4-th -> 8-th node, seq is:[0, 45, 36, 18, 93, 72, 30, 48, 53, 15, 35]
8. 上面检查发现53符合要求,不用动了。继续创建堆,这个时候mid=3,也就是要看节点18了,找最大孩子节点48,索引i=7,没办法了,交换吧,代码输出和结果示意图如下:
3-th -> 7-th node, seq is:[0, 45, 36, 48, 93, 72, 30, 18, 53, 15, 35]
9. 交换后18的索引成了7,对7继续递归调用最大化堆化操作,检查满足结束条件,mid继续减少,mid=2,对索引为2,节点为36的点调用最大化堆化操作,不重复了,最大的孩子节点为93,索引i=4,没办法,交换位置:
2-th -> 4-th node, seq is:[0, 45, 93, 48, 36, 72, 30, 18, 53, 15, 35]
对36节点的索引4继续调用最大堆堆化操作,发现最大孩子是节点53,索引为8,没办法,互换:
4-th -> 8-th node, seq is:[0, 45, 93, 48, 53, 72, 30, 18, 36, 15, 35]
36拉下来之后,继续迭代调用最大化堆化函数,满足结束条件
10. mid=1,调用最大堆堆化函数,最大的孩子节点是93,索引为2,互换:
1-th -> 2-th node, seq is:[0, 93, 45, 48, 53, 72, 30, 18, 36, 15, 35]
对45,索引为2的继续迭代调用最大化堆化,发现最大的孩子节点是72,索引为5,没办法了,继续互换:
2-th -> 5-th node, seq is:[0, 93, 72, 48, 53, 45, 30, 18, 36, 15, 35]
11. 按照上述执行完之后打印结果,如下:
12. 构建堆思路继续整理下:
(1)找要开始处理的点的索引,参考数组存放堆的数学公式,节点i的父节点索引(i/2),左子节点索引(2i),右子节点索引(2i+1)。而且我们已知对于节点数为n的完全二叉树,叶子节点数n0=n/2,所以要找第一个有叶子的节点的索引很简单:n为偶数,n/2;n为奇数,(n+1)/2。这个值求出来后赋给mid。
(2)对当前的mid对应的节点执行最大堆堆化操作,然后mid递减,直到mid>0时停止,这步就能完成构建堆的任务。
13. 最大堆化思路继续整理下:
(1)传入的索引,要检查下是否存在子节点,也就是检查下(2i)是否小于序列长度。还是使用上面的数学公式设计这个边界条件。满足则执行下面的其它操作,否则直接返回。
(2)找当前索引i的最大的子节点的索引mc,这里找到的还是索引,所有的操作均再索引上进行。
(3)比较当前索引i和索引mc对应的节点值的大小,如果当前找到比i对应节点还大,则交换位置,同时递归调用最大堆化操作
14. 最大子节点思路继续整理:
(1)输入当前索引i,找到左孩子索引(2i),右孩子索引(2i+1).
(2)如果左孩子大于当前节点,则最大值等于左孩子,否则还是当前节点最大。
(3)如果右孩子大于最大节点,则最大值等于右孩子。
(4)最后返回当前节点索引下找到的最大值对应节点的索引
15. 好,算法整体完成,思路啰嗦点,但是递归看起来很清晰,时间复杂度么:构造——O(n),最大堆化——O(logn),完整算法代码如下,里面包含了打印功能:
#coding=utf-8
from __future__ import print_function
import math, random
import heapq
class BinHeap:
def __init__(self):
self.heapList = [0]
self.currentSize = 0
def max_heapify_rec(self, i):
if (i * 2) <= self.currentSize:
mc = self.maxChild(i)
if self.heapList[i] < self.heapList[mc]:
tmp = self.heapList[i]
self.heapList[i] = self.heapList[mc]
self.heapList[mc] = tmp
print("%d-th -> %d-th node, seq is:%s" % (i, mc, self.heapList))
self.max_heapify_rec(mc)
def maxChild(self, i):
leftchild = i * 2
rightchild = i * 2 + 1
if leftchild <= self.currentSize and self.heapList[leftchild] > self.heapList[i]:
largest = leftchild
else:
largest = i
if rightchild <= self.currentSize and self.heapList[rightchild] > self.heapList[largest]:
largest = rightchild
return largest
def max_heapify(self, i):
while (i * 2) <= self.currentSize:
mc = self.maxChild[i]
if self.heapList[i] < self.heapList[mc]:
tmp = self.heapList[i]
self.heapList[i] = self.heapList[mc]
self.heapList[mc] = tmp
i = mc
def buildHeap(self, alist):
mid = len(alist) // 2
self.currentSize = len(alist)
self.heapList = [0] + alist[:]
print("The initial seq is %s:" % self.heapList)
while (mid > 0):
self.max_heapify_rec(mid)
mid = mid - 1
return self
def heapsort(alist):
sortedh = []
heapify(alist)
while alist:
sortedh.append(heappop(alist))
return sortedh
def print_tree(array):
index = 1
depth = math.ceil(math.log(len(array), 2))
sep = ' '
for i in range(int(depth)):
offset = 2 ** i
print(sep * (2 ** (int(depth) - i - 1) - 1), end = ' ')
line = array[index:index+offset]
for j, x in enumerate(line):
print("{:>{}}".format(x, len(sep)), end = ' ')
interval = 0 if i == 0 else 2 ** (int(depth) - i) - 1
if j < len(line) - 1:
print(sep * interval, end = ' ')
index += offset
print()
A = [45, 36, 18, 53, 72, 30, 48, 93, 15, 35]
bh = BinHeap()
bh.buildHeap(A)
print_tree(bh.heapList)