比较两棵二叉树是否相同/一棵二叉树是否是另一棵二叉树的子树/一棵二叉树是否是另一颗二叉树的子结构
本文章讨论两个问题:
①如何判断两棵二叉树的结构是一样的、对应的每个结点都有着相同的值。--即判断两棵二叉树是一样的
②给定两棵二叉树,如何判断一棵二叉树是另一棵二叉树的子结构
③给定两棵二叉树,如何判断一棵二叉树是另一棵二叉树的子树
注意,子结点与子树不同。如下图所示,2,3,4都是1的子结构但是只有4是1的子树。
一、判断两个二叉树是否完全一致
(1)由于先序序列和中序序列可以完全确定一颗二叉树,因此可以将两个二叉树的先序序列和中序序列求出来,然后比较二者是否一致。
(2)递归,比较根结点是否一样;如果根结点一样,再继续比较根的左右孩子是否一样。
1 public boolean sameTree2(BinaryNode<T> root1, BinaryNode<T> root2){ 2 //树的结构不一样 3 if((root1 == null && root2 != null) || (root1 != null && root2 == null)) 4 return false; 5 6 //两棵树最终递归到终点时 7 if(root1 == null && root2 == null) 8 return true; 9 10 if(root1.element.compareTo(root2.element) != 0) 11 return false; 12 else 13 return sameTree2(root1.left, root2.left) && sameTree2(root1.right, root2.right); 14 }
二、一棵二叉树是否是另一棵二叉树的子树
错误解法:此时不可以用得到两棵树的先序(中序、后序)遍历序列1、2,然后利用KMP算法判断2是否是1的子序列。
原因:因为一个序列不能唯一构建一棵二叉树,如下图所示,1的先序遍历序列为 ABDEC,2的先序遍历序列为BDE,但是2不是1的子树。、
与判断是否是子结构类似,只是在isSubtree的递归出口有些差别。
//判断以当前root1为根的树,和以root2为根的树,是否是相同的树 public static boolean isSubtree(TreeNode root1,TreeNode root2) { if(root1==null&&root2!=null) return false; if(root1!=null&&root2==null) return false; if(root2==null&&root1==null) return true; if(root1.val==root2.val) { return isSubtree(root1.left,root2.left)&&isSubtree(root1.right,root2.right); } else return false; }
三、一棵二叉树是否是另一颗二叉树的子结构
错误解法:判断子结构问题同样不能用子序列的方式进行,如图所示。
原因1: 是子结构,不一定是子序列。 树1先序遍历 ABDEC,树3先序遍历ABC,3是1的子结构,但是序列不是其子序列。
原因2:是子序列,不一定是子结构。如问题二图所示。
1 /** 2 public class TreeNode { 3 int val = 0; 4 TreeNode left = null; 5 TreeNode right = null; 6 7 public TreeNode(int val) { 8 this.val = val; 9 10 } 11 12 } 13 */ 14 public class Solution { 15 //判断以当前root1为根的树,和以root2为根的树,是否是根相同的子结构 16 public static boolean isSubtree(TreeNode root1,TreeNode root2) { 17 if(root1==null&&root2!=null) 18 return false; 19 if(root2==null) 20 return true; 21 if(root1.val==root2.val) 22 { 23 return isSubtree(root1.left,root2.left)&&isSubtree(root1.right,root2.right); 24 } 25 else 26 return false; 27 } 28 29 //只用一个函数,由于需要递归,递归出口与判断初始树是否为空矛盾。 30 //此函数当前节点不相等则继续比较左右子树,与上面的函数不同 31 //将判断当前子树与目标子树是否相同作为一个单独的函数(isSubtree)。 32 public static boolean HasSubtree(TreeNode root1,TreeNode root2) { 33 if(root1==null&&root2!=null) 34 return false; 35 if(root2==null) 36 return false; //空树不是任一树的子结构 37 boolean tag=false; 38 tag=isSubtree(root1,root2); 39 if(tag==true) 40 return true; 41 else{ 42 tag=HasSubtree(root1.left,root2); //此处的函数调用为HasSubtree,因为isSubtree只判断当前根节点相同的子结构,不会递归判断子树 43 if(tag==true) 44 return true; 45 else 46 return HasSubtree(root1.right,root2); 47 } 48 } 49 }
另外拓展:三种遍历序列中,中序遍历+前序/后序即可重建二叉树。但是只有前序和后序遍历序列无法重建二叉树。