二叉树(二)判断是否是平衡二叉树,完全二叉树,求完全二叉树节点个数

平衡二叉树:在这颗树中任何一个节点,其左子树和右子树的高度差不超过一

 判断一棵二叉树是否平衡 可以用递归的方式 类似于求二叉树的深度

完全二叉树:略

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));
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值