【Lintcode】130. Heapify

题目地址:

https://www.lintcode.com/problem/heapify/description

将一个数组堆化,就地变为最小二叉堆。

先设置一个percolateDown的函数,它的作用是对根节点为 i i i的二叉堆进行下滤操作。然后从整个二叉堆最后一个有孩子的节点到堆顶依次进行下滤操作即可。代码如下

public class Solution {
    /*
     * @param A: Given an integer array
     * @return: nothing
     */
    public void heapify(int[] A) {
        // write your code here
        // A中最后一个有孩子的元素下标是(A.length - 2) >> 1
        for (int i = (A.length - 2) >> 1; i >= 0; i--) {
            percolateDown(A, i);
        }
    }
    
    private void percolateDown(int[] A, int i) {
    	// 为判断A[i]是否破坏堆的性质,我们需要找到A[i]以及它的两个孩子三者中最小值的下标
    	// 如果i有孩子,就进入循环
       	while ((i << 1) + 1 < A.length) {
       		// 先假设左孩子是三者中最小值的下标
            int child = (i << 1) + 1;
            // 如果存在右孩子,且右孩子比左孩子还小,就把child更新为右孩子
            if ((i << 1) + 2 < A.length && A[child] > A[(i << 1) + 2]) {
                child = (i << 1) + 2;
            }
            // 如果A[i]已经是三者中最小值了,就不用下滤了,退出循环
            if (A[i] <= A[child]) {
                break;
            }
            // 否则把A[i]换下去
            swap(A, i, child);
            
            // 从下一层开始继续下滤
            i = child;
        }
    }
    
    private void swap(int[] A, int i, int j) {
        int tmp = A[i];
        A[i] = A[j];
        A[j] = tmp;
    }
}

时间复杂度 O ( n ) O(n) O(n),空间 O ( 1 ) O(1) O(1)

时间复杂度证明:每一层在下滤中交换的次数最多是其高度(高度是指它所在的深度减去叶子层的深度),所以可知: T ( n ) ≤ ∑ i = 1 h − 1 2 h − 1 − i i = 2 h − 1 ∑ i = 1 h − 1 i 2 i < 2 h − 1 ∑ i = 1 ∞ 1 2 i − 1 = 2 h = n + 1 T(n)\le \sum_{i=1}^{h-1}2^{h-1-i}i=2^{h-1}\sum_{i=1}^{h-1}\frac{i}{2^i}<2^{h-1}\sum_{i=1}^{\infty}\frac{1}{2^{i-1}}=2^h=n+1 T(n)i=1h12h1ii=2h1i=1h12ii<2h1i=12i11=2h=n+1所以时间复杂度 O ( n ) O(n) O(n)

算法正确性证明:只需证明对于两个最小二叉堆,如果把它们接在一个树根下面分别作为左右孩子时,只需要对树根做下滤操作就可以使得整个二叉树满足堆性质(由算法的实现,不需要考虑complete的问题)。数学归纳法。如果两个堆的节点和等于 0 , 1 , 2 , 3 0,1,2,3 0,1,2,3,结论显然成立。假设对于左右堆节点和小于 n n n的时候结论成立。那么从树根开始下滤的时候,第一次下滤已经可保证一边的堆已经不需要调整了,而新的要调整的一边的树根下面接着两个节点数严格小于 n n n的堆,由数学归纳法,结论成立。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值