题目:
输入两颗二叉树A和B,判断B是不是A的子结构。二叉树结点的定义如下:
struct BinaryTreeNode{ int m_nValue; BinaryTreeNode* m_pLeft; BinaryTreeNode* m_pRight; }
思路:
判断是不是子结构可以分为两步:(1)在树A中找到和B的根结点的值一样的结点R(实际上就是树的遍历,可以用递归方法去遍历,也可以用循环的方法去遍历,终止条件遍历到达叶结点了)第二步再判断树A中以R为根结点的子树是不是包含和树B一样的结构(实际上也可以用递归的思路来考虑:如果结点R的值和树B的根结点不相同,则以R为根结点的子树和树B肯定不具有相同的结点;如果它们的值相同,则递归地判断它们各自的左右结点的值是不是相同。递归的终止条件是我们到达了树A或者树B的叶结点)。
代码实现:
第一步:找到树A中和B的根结点一样值的结点R
public class BinaryTreeNode { public int data; public BinaryTreeNode left; public BinaryTreeNode right; public BinaryTreeNode(int data) { this.data = data; } @Override public String toString() { return "BinaryTreeNode [data=" + data + ", left=" + left + ", right=" + right + "]"; } }
public boolean HasSubtree(BinaryTreeNode pRoot1, BinaryTreeNode pRoot2){ boolean result = false; if(pRoot1!=null && pRoot2!=null){ if(pRoot1.data == pRoot2.data){ result = DoesTree1HaveTree2(pRoot1, pRoot2); } if(!result){ result = HasSubtree(pRoot1.left, pRoot2); } if(!result){ result = HasSubtree(pRoot1.right, pRoot2); } } return result; }
第二步:判断树A中以R为根结点的子树是不是包含和树B一样的结构(判断是不是为空,避免了视图访问空指针而造成程序崩溃,同时也设置了递归调用的退出条件)
//判断子树的除根结点以外的结点是否相同 private boolean DoesTree1HaveTree2(BinaryTreeNode pRoot1, BinaryTreeNode pRoot2) { if(pRoot2 == null){ return true; } if(pRoot1==null){ return false; } if(pRoot1.data != pRoot2.data){ return false; } return DoesTree1HaveTree2(pRoot1.left, pRoot2.left) && DoesTree1HaveTree2(pRoot1.right, pRoot2.right); }
小结:
程序一定要注意边界条件的检查,即检查空指针。当树A或树B为空的时候,定义相应的输出。没有检查这种情况是很忌讳的事情。在二叉树相关的代码中有大量的指针操作,每一次使用指针的时候,我们都需在脑子里时刻保持着这个指针有没有是NULL的可能,如果有怎么处理?
提高代码质量3个标准:规范性(书写清晰、布局清晰、命名合理)、完整性(完成基本功能、考虑边界条件、做好错误处理)、鲁棒性(采取防御式编程、处理无效的输入)。