算法设计与分析——堆(二):维护堆的性质

分类目录:《算法设计与分析》总目录
相关文章:
·堆(一):基础知识
·堆(二):维护堆的性质
·堆(三):建堆
·堆(四):优先队列
·排序算法:堆排序
·利用heapq模块实现堆


heapify(arr, i)是用于维护最大堆性质的重要过程。它的输入为一个数组 A A A和一个下标 i i i

在调用heapify(arr, i)的时候,我们假定根结点为left(i)right(i)的二叉树都是最大堆,但这时 A [ i ] A[i] A[i]有可能小于其孩子,这样就违背了最大堆的性质。heapify(arr, i)通过让 A [ i ] A[i] A[i]的值在最大堆中“逐级下降”,从而使得以下标 i i i为根结点的子树重新遵循最大堆的性质。

def heapify(arr, i): 
    largest = i  
    l = 2 * i + 1     # left = 2*i + 1 
    r = 2 * i + 2     # right = 2*i + 2 
  
    if l < len(arr) and arr[i] < arr[l]: 
        largest = l 
  
    if r < len(arr) and arr[largest] < arr[r]: 
        largest = r 
  
    if largest != i: 
        arr[i],arr[largest] = arr[largest],arr[i]  # 交换
        heapify(arr, largest)

下图图示了heapify(arr, i)的执行过程。在程序的每一步中,从 A [ i ] A[i] A[i] A [ l e f t ( i ) ] A[left(i)] A[left(i)] A [ r i g h t ( i ) ] A[right(i)] A[right(i)]中选出最大的,并将其下标存储在 l a r g e s t largest largest中。如果 A [ i ] A[i] A[i]是最大的,那么以 i i i为根结点的子树已经是最大堆,程序结束。否则,最大元素是 i i i的某个孩子结点,则交换 A [ i ] A[i] A[i] A [ l a r g e s t ] A[largest] A[largest]的值。从而使 i i i及其孩子都满足最大堆的性质。在交换后,下标为 l a r g e s t largest largest的结点的值是原来的 A [ i ] A[i] A[i],于是以该结点为根的子树又有可能会违反最大堆的性质。因此,需要对该子树递归调用heapify(arr, i)
维护堆的性质

对于一棵以 i i i为根结点、大小为 n n n的子树,heapify(arr, i)的时间代价包括:调整 A [ i ] A[i] A[i] A [ l e f t ( i ) ] A[left(i)] A[left(i)] A [ r i g h t ( i ) ] A[right(i)] A[right(i)]的关系的时间代价 Θ ( 1 ) \Theta(1) Θ(1),加上在一棵以 i i i的一个孩子为根结点的子树上运行heapify(arr, i)的时间代价(这里假设递归调用会发生)。因为每个孩子的子树的大小至多为 2 n 3 \frac{2n}{3} 32n(最坏情况发生在树的最底层恰好半满的时候),我们可以用下面这个递归式刻画heapify(arr, i)的运行时间:
T ( n ) ≤ T ( 2 n 3 ) + Θ ( 1 ) T(n)\leq T(\frac{2n}{3}) + \Theta(1) T(n)T(32n)+Θ(1)
故递归式的解为 T ( n ) = O ( log ⁡ n ) T(n)=O(\log n) T(n)=O(logn)。也就是说,对于一个树高为 h h h的结点来说,heapify(arr, i)的时间复杂度是 O ( h ) O(h) O(h)

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

von Neumann

您的赞赏是我创作最大的动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值