判断是否为完全二叉树(两种方法)

完全二叉树也就是没有满的满二叉树,它的节点在每一层一定是连续分布的。如果出现哪一层中两个非空节点间隔一个空节点,那一定不是完全二叉树。如下图所示:
在这里插入图片描述
假设这棵完全二叉树有K层,因此我们可以总结一下完全二叉树的规律:

  • 前K-2层:每个节点都有两个孩子,节点饱和
  • 前K-1层:节点肯定是饱和的—>到达了最大值
  • 第K-1层:不一定所有的节点都有孩子节点,如果有孩子节点,至少要是左孩子节点,有可能出现不饱和节点

方法一:

从上面的规律中我们可以知道:

  1. 完全二叉树的前k-1层一定是包和节点,第k-1层就可能出现不饱和节点。
  2. 判断二叉树是否为一棵完全二叉树的关键就是找到第一个不饱和节点,再判断后续节点与当前不饱和节点的关系(即:找到第一个不饱和的节点之后,后序的所有节点不能有孩子节点才是完全二叉树)。
    • 不饱和节点有
      • 只有左孩子
      • 只有右孩子
      • 没有孩子;
  3. 不饱和节点和后续节点的关系
    • 叶子节点(没有孩子)或者只有左孩子的节点:也就是这两种不饱和的节点出现之后还需要判断后面的节点是否有孩子
    • 只有右孩子没有左孩子一定不是完全二叉树

综上,我们把代码的步骤理一下:

  • 空树:返回true
  • 树不为空:将根节点入队列,设置isLeafOrLeft=false(表示没有找到第一个不饱和节点),循环执行如下操作(循环条件:队列不为空):
    • 将队头元素出队列并标记:cur=queue.poll();
    • 找到第一个不饱和节点
      • 从第一个不饱和结点之后,所有节点不能有孩子,如果有左孩子或者右孩子:返回false
    • 没有找到第一个不饱和节点,继续按照层序遍历寻找:
      • cur节点(当前节点)左右孩子都存在:左孩子入队列,右孩子入队列
      • cur只有左孩子:即找到第一个不饱和节点,标记isLeafOrLeft=true
      • cur只有右孩子:找到不饱和节点,一定不是完全二叉树,返回false
      • cur是叶子节点:找到不饱和节点:标记isLeafOrLeft=true

代码实现:

//判断是否为完全二叉树---》用层序遍历的思想一层一层找不饱和节点,也就是需要借队列
public  boolean isCompleteTree(BTNode root)
{
     if(root==null)
     {
         return true;
     }
     Queue<BTNode> q=new LinkedList<>();
     q.offer(root);
     //是叶子节点或者只有左孩子的节点,也就是这两种不饱和的节点出现之后还需要判断后面的节点是否有孩子
     // 如果只有右孩子的不饱和节点一定不是完全二叉树
    // 一开始让不饱和节点置为false,找到之后设为true
    boolean isLeafOrLeft=false;
    while(!q.isEmpty()) {
        BTNode cur = q.poll();
        //得到第一个不饱和节点之后
        if (isLeafOrLeft) {
             //从第一个不饱和结点之后,所有节点不能有孩子
            if (null != cur.left || null != cur.right) {
                System.out.println("该二叉树不是完全二叉树");
                return false;
            }
       }//没找到不饱和节点就继续按照层序遍历寻找
       else {
            //cur节点左右孩子都存在
            if (null != cur.left && null != cur.right) {
                q.offer(cur.left);
                q.offer(cur.right);
            } else if (null != cur.left) {
                //只有左孩子:找到不饱和节点,标记isLeafOrLeft=true
                q.offer(cur.left);
                isLeafOrLeft = true;
            } else if (null != cur.right) {
                //只有右孩子:找到不饱和节点,一定不是完全二叉树,返回false
                System.out.println("该二叉树不是完全二叉树");
                return false;
            } else {
                //cur是叶子节点:找到不饱和节点:标记isLeafOrLeft=true
                isLeafOrLeft = true;
            }
        }
    }
    System.out.println("该二叉树是完全二叉树");
    return true;
}

上面这种方法在我们理清了判断是否为完全二叉树的关键之后,还是很容易写出的,同样是借助队列,还有另一种解题办法,来看看吧!

方法二:

判断是否为完全二叉树的关键也是找到不饱和节点,但是第二个方法减少了各种不饱和节点的判断,在代码上减少了一定的代码量,同时思路也简洁了不少。

思路:

由于完全二叉树在每一层非空节点都是一个接一个连续分布的,不可能出现两个非空节点之间交叉一个空节点,因此:

  • 我们可以通过层序遍历从上往下,从左往右将每一个节点(包括非空节点)都放到队列里
  • 在出队列的过程中,如果遇到空节点,则跳出循环
  • 跳出循环后,然后再判断队列中剩下的元素是否有非空节点
    • 有非空节点:非完全二叉树;
    • 没有非空节点(全是空节点):完全二叉树。

代码步骤:

1、树为空:返回true

2、树不为空:将二叉树的跟入队,并循环执行以下操作,循环条件:队列不为空;跳出循环条件:cur==null

  • 取出队头元素,cur=queue.poll()
  • 如果有左孩子:入队列
  • 如果有右孩子:入队列

3、当通过条件:cur==null跳出循环后,判断队列里边是否还有非空元素

  • 如果有非空元素:不是完全二叉树
  • 没有非空元素:是完全二叉树

代码:

public  boolean isCompleteTree(BTNode root)
{
	if(root==null) return false;
	Queue<BTNode> queue=new Linklisted<>();
	queue.offer(root);
	while(!queue.isEmpty())
	{
		BTNode cur=queue.poll();
		if(cur==null)
		{
			break;
		}else{
			if(cur.left!=null) queue.offer(cur.left);
			if(cur.right!=null) queue.offer(cur.right);
		}
	}
	//判断队列中剩余的元素是否为空
	while(!queue.isEmpty())
	{
		BTNode cur=queue.poll();
		if(cur!=null)  return false;
	}
	return true;
}
  • 114
    点赞
  • 386
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值