本章有两种实现思路:队列和递归套路,互为对数器
定义:
一棵树的叶子结点必须先有左节点再有右节点,如果有节点没有左节点,确有右节点,则不是完全二叉树。
思路
- 如果左节点为空,右节点不为空,false
- 如果之前碰到过不满的节点,再次碰到的左右节点存在的节点,false
static class Node{
int val;
Node left;
Node right;
public Node(int val) {
this.val = val;
}
}
public static boolean complateTree(Node head){
if(head==null)return true;
//是否碰到过不满的节点
boolean leaf = false;
Node l=null;
Node r=null;
LinkedList<Node> queue = new LinkedList<>();
queue.add(head);
while (!queue.isEmpty()){
Node cur = queue.poll();
l=cur.left;
r=cur.right;
if((l==null && r!=null)
//leaf为true证明碰到过不满的节点
//再次碰到左右子节点存在的节点,就不是完全二叉树
|| (leaf && (l!=null || r!=null))
){
return false;
}
if(l!=null){
queue.add(l);
}
if(r!=null){
queue.add(r);
}
if(l==null || r==null){
leaf=true;
}
}
return true;
}
递归套路
看下图,以头结点为中线,二叉树是慢慢从左往右依次变满的,根据这个思路,可以总结出几个重点:
- 左树完全,右树满,左树高度=右树高度+1
- 左树满,右树满,左树高度=右树高度+1
- 左树满,右树完全,左树高度=右树高度
- 左树满,右树满,左树高度=右树高度
- 从上面的思路提取公共条件:
-
1.是否满,
-
2.是否完全,
-
3.树高
-
/**
* 递归套路判断是否是完全二叉树
* 思路:以头结点为中线,看树是否从左到右依次变满
* 1.左树完全,右树满,左树高度=右树高度+1
* 2.左树满,右树满,左树高度=右树高度+1
* 3.左树满,右树完全,左树高度=右树高度
* 4.左树满,右树满,左树高度=右树高度
* 从上面的思路提取公共条件:
* 1.是否满,
* 2.是否完全,
* 3.树高
*/
static class Info{
boolean isFull;//是否完全
boolean isCBT;//是否满
int height;//树高
public Info(boolean isFull, boolean isCBT, int height) {
this.isFull = isFull;
this.isCBT = isCBT;
this.height = height;
}
}
public static boolean complateTree2(Node head){
return process(head).isCBT;
}
public static Info process(Node head){
if(head==null){
return new Info(true,true,0);
}
Info leftInfo = process(head.left);
Info rightInfo = process(head.right);
//收集左右子树信息,拼装返回信息
int height= Math.max(leftInfo.height, rightInfo.height)+1;
boolean isFull= leftInfo.isFull && rightInfo.isFull && leftInfo.height== rightInfo.height;
boolean isCBT = false;
if(leftInfo.isCBT && rightInfo.isFull && leftInfo.height==rightInfo.height+1){
isCBT=true;
}
if(leftInfo.isFull && rightInfo.isFull && leftInfo.height==rightInfo.height+1){
isCBT=true;
}
if(leftInfo.isFull && rightInfo.isCBT && leftInfo.height==rightInfo.height){
isCBT=true;
}
if(leftInfo.isFull && rightInfo.isFull && leftInfo.height==rightInfo.height){
isCBT=true;
}
return new Info(isFull,isCBT,height);
}
生成测试二叉树
public static Node generateRandomNode(int maxLevel,int maxValue){
return generate(1,maxLevel,maxValue);
}
private static Node generate(int level,int maxLevel,int maxValue){
if(level>maxLevel || Math.random()<0.5){
return null;
}
Node head = new Node((int)(Math.random()*maxValue));
head.left=generate(level+1,maxLevel,maxValue);
head.right=generate(level+1,maxLevel,maxValue);
return head;
}
测试
public static void main(String[] args) {
Node head = new Node(1);
head.left = new Node(2);
head.right = new Node(3);
head.left.left = new Node(4);
head.left.right = new Node(5);
head.right.left = new Node(6);
head.right.right = new Node(7);
System.out.println(complateTree(head));
System.out.println(complateTree2(head));
int maxLevel=5;
int maxValue=5000;
int testTimes=10000000;
for (int i = 0; i < testTimes; i++) {
Node node = generateRandomNode(maxLevel, maxValue);
if(complateTree(node)!=complateTree2(node)){
System.out.println("Oops");
}
}
System.out.println("finished");
}