平衡二叉树:在这颗树中任何一个节点,其左子树和右子树的高度差不超过一
判断一棵二叉树是否平衡 可以用递归的方式 类似于求二叉树的深度
完全二叉树:略
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
求解一颗二叉树的深度:
public class Solution {
public int TreeDepth(TreeNode root) {
if(root==null) return 0;
int a=TreeDepth(root.left);
int b=TreeDepth(root.right);
return a>b? a+1:b+1;
}
}
判断是否是平衡二叉树:
//如果值不是-1 则为平衡二叉树,返回的是这棵树的高度
public boolean IsBalanced_Solution(Node root) {
int res=isBinaryTree(root);
if(res==-1) return false;
return true;
}
public int isBinaryTree(Node head ) {
if(head==null) return 0;
int a=isBinaryTree(head.left);
if(a==-1) return -1;
int b=isBinaryTree(head.right);
if(b==-1) return -1;
if(Math.abs(a-b)>1) return -1;
return a>b?a+1:b+1;
}
判断是否是完全二叉树:思路(见注释)
public static boolean isCompleteBT(Node head) {
if (head == null)
return true;
Queue<Node> queue = new LinkedList<Node>();
boolean flag = false;
queue.add(head);
Node l;
Node r;
while (!queue.isEmpty()) {
// 从队列中弹出第一个元素,把其左右结点压入队列,以实现按层遍历(如果不存在左右结点则不能压入)
head = queue.poll();
l = head.left;
r = head.right;
if (l != null)
queue.add(l);
if (r != null)
queue.add(r);
// 开始判断
// 情况一:只有右孩子 没有左孩子 一定不是完全二叉树
// 情况二 左右孩子都为空 或者 只有左孩子没有右孩子
// 则以后的节点一定都为叶子节点(即没有孩子) 在此处做一个标记
if (flag) {
if(l!=null||r!=null) return false; //不是叶子节点
} else {
if(l==null&&r!=null) return false;//只有左孩子没有右孩子
//可简化为只要没有右孩子 flag=true;
if((l!=null&&r==null)||(l==null&&r==null)) flag=true;
}
}
return true;
}
求完全二叉树的结点个数:要求时间复杂度低于O(n)
时间复杂度:O([logn]^2)
函数:先得到高度,然后进入递归过程
public static int TreeNum(Node head) {
if (head == null)
return 0;
int h = mostLeft(head, 1);
return BS(head, 1, h);
}
递归过程:
根节点从第一层开始计数。 h为要求解的完全二叉树的高度
三个参数分别是当前树结点,所在层,完全二叉树的高度
a为当前节点的右子树 向下遍历, 能够达到的深度
当能够达到完全二叉树的最后一层时,当前节点的左子树一定为满二叉树,可直接计算结点个数 然后把右子树递归
当不能达到最后一层时,(一定为倒数第二层) 此右子树一定是满二叉树,直接计算结点个数,然后把左子树递归
private static int BS(Node head, int level, int h) {
//最后一层结点进入此函数时直接返回结点个数1
if (level == h)
return 1;
//得到其子树向下遍历的能够达到的深度
int a = mostLeft(head.right, level + 1);
if (a == h) {
return (1 << (h - level)) + BS(head.right, level + 1, h);
} else{
return (1 << (h - level - 1)) + BS(head.left, level + 1, h);
}
}
辅助函数:向下遍历,得到深度的函数
//传入参数 当前节点 所在层
private static int mostLeft(Node head, int level) {
// 如果传进来的节点为空 返回高度-1()刚刚已经加了高度 再减回去
while (head != null) {
head = head.left;
level++;
}
return level - 1;
}
由于从根节点向下递归时,每进行一层,都要执行一次moreleft函数 (logN) 每执行完此函数后,都可直接计算一半的子树结点,然后对另一半子树进行递归,进入递归的节点一共只有logN(每层进入一个)所以复杂度为O(logn*logn)
准确的计算为 log2 1+log2 2 +log2 3+...+log2 N =O(logN*logN)
(求解完全二叉树结点个数 )以下内容可忽略
问题是求解完全二叉树的结点个数,在递归前先得到要求解的完全二叉树的高度H。
传入一个节点A(设在第level层),A结点的右子树(第level+1) 开始 向下层层遍历level++,直到叶子节点为止,得到深度 hl与H比较,
hl==H时(即能够遍历到要求解的完全二叉树的最后一层),证明结点A的左子树一定是高度为H-level的满二叉树。 然后可以直接计算其结点个数+1(结点A),然后把右子树加入递归过程(计算完全二叉树的结点个数) 相加
hl!=H时,则右子树一定是H-level-1的满二叉树 ,直接计算右子树结点个数+1(结点A),与 把左子树加入递归过程得到的值 相加。
在全部的递归过程中要知道此完全二叉树的高度,在计算子问题时,要层层遍历 得到子树的能够走得深度,所以要有一个辅助函数便是计算深度 hl的函数。还要有一个参数,记录当前子树是第几层,便于计算高度时直接向下累加。
)
求节点个数和是否是完全二叉树的测试代码:(可忽略)
package BinaryTree;
import java.util.LinkedList;
import java.util.Queue;
//if else
//问题一:是否是完全二叉树 complete binary Tree
//求解完全二叉树节点个数:
public class isCBT {
// 树结点
public static class Node {
public int value;
public Node left;
public Node right;
public Node(int data) {
this.value = data;
}
}
public static boolean isCompleteBT(Node head) {
if (head == null)
return true;
Queue<Node> queue = new LinkedList<Node>();
boolean flag = false;
queue.add(head);
Node l;
Node r;
while (!queue.isEmpty()) {
// 从队列中弹出第一个元素,把其左右结点压入队列,以实现按层遍历(如果不存在左右结点则不能压入)
head = queue.poll();
l = head.left;
r = head.right;
if (l != null)
queue.add(l);
if (r != null)
queue.add(r);
// 开始判断 情况一:只有右孩子 没有左孩子 一定不是完全二叉树
// 情况二 左右孩子都为空 或者 只有左孩子没有右孩子
// 则以后的节点一定都为叶子节点(即没有孩子) 在此处做一个标记
if (flag) {
if (l != null || r != null)
return false; // 不是叶子节点
} else {
if (l == null && r != null)
return false;// 只有左孩子没有右孩子
// 可简化为只要没有右孩子 flag=true;
if ((l != null && r == null) || (l == null && r == null))
flag = true;
}
}
return true;
}
// 求解完全二叉树节点个数:
public static int TreeNum(Node head) {
if (head == null)
return 0;
int h = mostLeft(head, 1);
return BS(head, 1, h);
}
//根节点从第一层开始计数。 h为要求解的完全二叉树的高度
//三个参数分别是当前树结点,所在层,完全二叉树的高度
private static int BS(Node head, int level, int h) {
//最后一层结点进入此函数时直接返回结点个数1
if (level == h)
return 1;
//得到其子树向下遍历的能够达到的深度
int a = mostLeft(head.right, level + 1);
if (a == h) {
// head 的左子树为满二叉树
return (1 << (h - level)) + BS(head.right, level + 1, h);
} else{
//右子树是满二叉树
return (1 << (h - level - 1)) + BS(head.left, level + 1, h);
}
}
//传入参数 当前节点 所在层
private static int mostLeft(Node head, int level) {
// 如果传进来的节点为空 返回高度-1()刚刚已经加了高度 再减回去
while (head != null) {
head = head.left;
level++;
}
return level - 1;
}
public static void main(String[] args) {
/*
* Node head = new Node(4); head.left = new Node(2); head.right = new Node(6);
* head.left.left = new Node(1); head.left.right = new Node(3); head.right.left
* = new Node(5);
*/
// System.out.println(isBST(head));
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);
System.out.println(TreeNum(head));
}
}