vlambda博客
学习文章列表

完全二叉树节点的计算(2021-8-3)

完全二叉树的节点个数

2021-8-3打卡LeetCode的第222题--完全二叉树的节点个数,借此机会了解一下完全二叉树的特性,以及怎么高效的计算二叉树的节点个数。我们通过递归可以计算普通二叉树的节点个数,通过一个公式可以 就可以满二叉树的节点个数。

前情提要--满二叉树与完全二叉树的区别

  • 满二叉树
    一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是(2^k) -1 ,则它就是满二叉树。一颗树深度为h,最大层数为k,深度与最大层数相同,k=h;它的叶子数是:2^h第k层的结点数是:2^(k-1)总结点数是:2^k-1(2的k次方减一)总节点数一定是奇数。
  • 完全二叉树
    完全二叉树的节点数是任意的,从形式上讲它是个缺失的的三角形,但所缺失的部分一定是右下角某个连续的部分,最后那一行可能不是完整的,对于k层的完全二叉树,节点数的范围2^ (k - 1) -1 < N< 2^k - 1;设二叉树的深度为h,除第 h 层外,其它各层 (1~h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树
  • 总结:说白了,满二叉树完全二叉树的一种特殊情况,是完全二叉树不一定是满二叉树,是满二叉树一定是完全二叉树。如果他的最底下一层不是满的,且节点都集中在左子树,那么它就是一颗完全二叉树。那么这里离可以得出一个结论,我们从根节点一直往它的左子树走一直走到底的深度应该就是树的高度,一直往右子树走到底可能有两种情况,如果深度等于树的高度那么他就是一颗满二叉树,如果比树的高度小1,那他就是一颗完全二叉树。

解题思路

这样的,如果一颗树是满二叉树我们就直接用公式 计算,如果他是一颗普通的二叉树,我们就按照普通的递归思维去计算它的所有节点。但是完全二叉树他比较特殊,它是介于满二叉树和普通二叉树之间的一种树。所以我们用这两种思维来计算就可以高效计算完全二叉的节点。如果它的子树是一个满二叉树,那么我们就直接用公式计算,省去了遍历的时间,所以啊,我们不得已才递归的去计算。

递归计算普通二叉树节点个数

public int SumNodes(TreeNode root){
        if(root==nullreturn 0;
        int leftNodes=SumNodes(root.left);
        int rightNodes=SumNodes(root.right);
        return leftNodes+rightNodes+1;
    }

计算完全二叉树节点个数代码实现

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */

class Solution {
    public int countNodes(TreeNode root) {
      if(root==nullreturn 0;
      TreeNode nodeLeft=root.left,nodeRight=root.right;
      int leftDeep=1,rightDeep=1;
      //计算左子树的高度
      while(nodeLeft!=null){
           leftDeep++;
           nodeLeft=nodeLeft.left;
      }
      //计算右子树的右边高度
       while(nodeRight!=null){
           rightDeep++;
           nodeRight=nodeRight.right;
      }
      //如果右子树右边的高度等于左子树的高度,就是一颗满二叉树,直接按照公式计算
      //如果不等于,那么以这个节点为根的树就是完全二叉树,我们就递归处理
      return rightDeep==leftDeep? (int)Math.pow(2,leftDeep)-1:countNodes(root.left)+countNodes(root.right)+1;
    }
}

总结

其实很难看出哪里做了优化,不就是判断一开始做了一个判断嘛,是满二叉树就直接公式计算,不是满二叉树还得按照常规的递归去计算。对了,优化就就优化在整个递归里面。你想一下,我们虽然递归了,但是你想一下,我们递归的是它以他左右孩子节点为根的子树,如果说它的左子树是一颗满二叉树,那么不就是省去了很多的时间吗?它的左子树一定是存在一颗小的满二叉树的,这样我们就避免了去遍历每一个节点。