判断一棵二叉树是否为另一棵二叉树的子结构(JAVA版本)

分析:判断root1是否为root2的子树?首先,必须先找到树1中与树2的根节点相同的节点,然后判断从该节点开始root1中是否root2的结构;若有,则返回true,若没有,则返回false?答案是No! 因为二叉树root1中可能含有值相同的节点,所以,如果没有找到,就需要继续遍历root1.
Way: 先设计一个函数,isSame(root1,root2)判断给定相同根节点的两子树是否一样?再设计一个函数,递归遍历二叉树root1各个节点,当找到相同节点时,就调用isSame()方法判断是否具有相同的结构,若没有,则继续遍历,若有,递归返回。

核心实现代码块:

	public static boolean isSame(TreeNode<Character> root1,TreeNode<Character> root2){
		if(root2==null)
			return true;
		
		if(root1==null)
			return false;//此时root2不为空,而root1却为空了,所以root2不是一的子结构
		
		if(!root1.data.equals(root2.data))
			return false;		
		
		return isSame(root1.leftChildren,root2.leftChildren)&&isSame(root1.rightChildren,root2.rightChildren);
	}
递归遍历:

	//判断是否子树结构
	public static boolean isSubTree(TreeNode<Character> root1,TreeNode<Character> root2){
		if(root2==null)
			return true;//如果root2我空节点,则是root1的子树
		if(root1!=null){
			if(root1.data.equals(root2.data) && isSame(root1,root2)){	
				//相等成立,表示在树1中找到了与树2根节点值相同的节点
				//****root1中可能有多个节点与root2根相等,仅当是子结构才返回,若不是则继续遍历
					return true;
			}else{
				//注意:此处不能分开写,递归理解:只要左子树或右子树中有一个包含子树即说明是root2是root1的子树
				//若分开写,则左子树若判断除了是子树,在当前栈中返回了一个true,由于递归栈深度大,无法传递回来
				return isSubTree(root1.leftChildren,root2) || isSubTree(root1.rightChildren,root2);	
			}
		}
		return false;
	}
实例:
root1:
	    8
	   / \
	  8   7
	 / \
	9   2
	   / \
	  4   7
root2:
	    8
	   / \
	  8   7
完整代码:

(包含树的节点定义、前序创建、中序遍历)

class TreeNode<T> {
	T data;
	TreeNode<T> leftChildren;
	TreeNode<T> rightChildren;
	public TreeNode(T data){
		this.data=data;
		this.leftChildren=null;
		this.rightChildren=null;
	}
}

public class Mao {

	public static void main(String[] args) {
		
		//创建2颗二叉树
		String str1="889##24##7##7##";
		String str2="89##2##";
		
		StringBuilder sb1=new StringBuilder(str1);
		StringBuilder sb2=new StringBuilder(str2);
		TreeNode<Character> root1=recurseCreateTree(sb1);
		TreeNode<Character> root2=recurseCreateTree(sb2);
		System.out.print("inOrder Tree1: ");
		inOrder(root1);
		System.out.print("\ninOrder Tree2: ");
		inOrder(root2);
		
		//判断
//		root1=root2=null;   // true
//		root1=null;     //false
//		root2=null;     //false
//		root2.leftChildren.data='3';     //false
		System.out.println("\n Tree2 is subTree of Tree1? "+isSubTree_better(root1,root2));
	}
	
	//判断是否子树结构
	public static boolean isSubTree(TreeNode<Character> root1,TreeNode<Character> root2){
		if(root2==null)
			return true;//如果root2我空节点,则是root1的子树
		if(root1!=null){
			if(root1.data.equals(root2.data) && isSame(root1,root2)){	
				//相等成立,表示在树1中找到了与树2根节点值相同的节点
				//****root1中可能有多个节点与root2根相等,仅当是子结构才返回,若不是则继续遍历
					return true;
			}else{
				//注意:此处不能分开写,递归理解:只要左子树或右子树中有一个包含子树即说明是root2是root1的子树
				//若分开写,则左子树若判断除了是子树,在当前栈中返回了一个true,由于递归栈深度大,无法传递回来
				return isSubTree(root1.leftChildren,root2) || isSubTree(root1.rightChildren,root2);	
			}
		}
		return false;
	}
	
	//上述方法更好的可以写为:(尤其是在普通树结构中)
	public static boolean isSubTree_better(TreeNode<Character> root1,TreeNode<Character> root2){
		
		if(root2==null)
			return true;
		boolean flag=false;
		if(root1!=null){
			if(root1.data.equals(root2.data)){
				flag=isSame(root1,root2);
			}
			if(!flag)
				flag=isSubTree_better(root1.leftChildren,root2);
			if(!flag)
				flag=isSubTree_better(root1.rightChildren,root2);
		}
		
		return flag;
	}
	
	//比较两棵树是否一样
	public static boolean isSame(TreeNode<Character> root1,TreeNode<Character> root2){
		if(root2==null)
			return true;
		
		if(root1==null)
			return false;//此时root2不为空,而root1却为空了,所以root2不是一的子结构
		
		if(!root1.data.equals(root2.data))
			return false;		
		
		return isSame(root1.leftChildren,root2.leftChildren)&&isSame(root1.rightChildren,root2.rightChildren);
	}

	//递归创建二叉树
	public static TreeNode<Character> recurseCreateTree(StringBuilder str){
		TreeNode<Character> node=null;
		char data=str.toString().charAt(0);
		str.delete(0,1);
		if('#'!=data){
			node=new TreeNode<Character>(data);
			node.leftChildren=recurseCreateTree(str);
			node.rightChildren=recurseCreateTree(str);
		}
		return node;
	}

	//二叉树的前序遍历
	public static void inOrder(TreeNode<Character> root){
		if(root!=null){
			inOrder(root.leftChildren);
			System.out.print(root.data+" ");
			inOrder(root.rightChildren);
		}
	}
}
输出结果为:

inOrder Tree1: 9 8 4 2 7 8 7 
inOrder Tree2: 9 8 2 
 Tree2 is subTree of Tree1? true
总结:本题重点在对二叉树的操作上,需要深入的理解递归的使用,以自己的见解(很浅):不需要深入考虑复杂的递归调用内部,而是单纯的将原问题划分子问题,如上述方法,出去对节点的null判断,实际就是在root1中找到与root2相等的节点,判断是否是子结构;如果不是,再看root1的左子树是否包含root2结构,再没有,就看右子树是否包含root2结构;最后加上个递归结束条件,root1传入的值为null结束。(如果太纠结递归那个过程很容易头晕脑胀的,所以还是简单点思考吧!)



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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值