本文章討論兩個問題:
①如何判斷兩棵二叉樹的結構是一樣的、對應的每個結點都有着相同的值。--即判斷兩棵二叉樹是一樣的
②給定兩棵二叉樹,如何判斷一棵二叉樹是另一棵二叉樹的子結構
③給定兩棵二叉樹,如何判斷一棵二叉樹是另一棵二叉樹的子樹
注意,子結點與子樹不同。如下圖所示,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 }
另外拓展:三種遍歷序列中,中序遍歷+前序/后序即可重建二叉樹。但是只有前序和后序遍歷序列無法重建二叉樹。