堆
堆:是一个数组,近似的完全二叉树,除了最底层外,该树是完全充满的.
最小堆:A[i] <= A[2i] && A[i] <= A[2i+1]
最大堆:A[i] >= A[2i] && A[i] >= A[2i+1]
下标从1开始算起
维护堆
max_heapify(A, i):维护最大堆的性质,让A[i]的值逐级下降
if 2*i <= len(A) and A[2*i] > A[i]:
largest = 2*i
else:
largest = i
if 2*i+1 <= len(A) and A[2*i+1] > A[i]:
largest = 2*i+1
else:
largest = i
if largest != i:
A[i],A[largest] = A[largest],A[i]
max_heapify(A,largest)
时间复杂度:(见算法导论第三版6.2节)
对于一个以i为根节点、大小为n的子树,交换值的代价为O(1),加上,以i的一个孩子为根节点的子树运行max_heapify的时间,每个孩子的子树的大小至多为2n/3(最坏情况发生在树的最底层恰好半满的时候)
这儿的2n/3的推导:
1、假设有一个包含n个元素的堆, 计算高度为 h=k 的节点数的上限
2、假设有一个完全二叉树,其中底层正好半满,即有x个节点。我们可以通过添加x个节点来构造一个满二叉树
3、满二叉树的大小为 **n + x = 2x * 2 - 1 = 4x - 1**。因此,我们有 **n = 3x - 1**,进而 **x = (n + 1) / 3**。
4、在满二叉树中,第i层的节点数目为 **(满树大小 - 1) / 2**。代入上述结果,我们得到 **2x - 1 = 2n/3 - 1/3 < 2n / 3**。
因此,在一个最大堆中,节点i的子树大小至多为2n/3
由此,
T(n) ≤ T(2n/3) + O(1) ----> T(n)=O(lg n)
即对于一个树高为h的节点,该操作的时间复杂度是O(h)。
建堆
最大堆:自底向上
build-max-heap(A):从最后一个非叶子节点开始,逐级向上维护最大堆的性质
A.heap-size = len(A)
for i in range(len(A)//2,0,-1):
max_heapify(A,i)
时间复杂度
初看是O(n lgn),精确是:O(n)
1、高为h的 至多节点个数
2、线性时间构造最大堆
这儿推导不是很明白!!!再看!!!
堆排序
heapsort(A):
build-max-heap(A)
for i in range(len(A),1,-1):
A[1],A[i] = A[i],A[1]
A.heap-size = A.heap-size - 1
max_heapify(A,1)
标签:最大,max,构造,heapify,二叉树,largest,线性,2n,节点
From: https://www.cnblogs.com/xuan01/p/18141766