题目:输入两颗二叉树A和B ,判断B是不是A的子结构。
想到关于二叉树的题目,基本可以按照递归的思路来做,很快写出以下代码:
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
class Solution {
public:
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
{
if(pRoot1==NULL)
return false;
else if(pRoot2==NULL||(pRoot2!=NULL&&(pRoot1->val==pRoot2->val&&pRoot2->left==NULL&&pRoot2->right==NULL)))
return true; //开始此处pRoot==NULL没写,直接段错误,想了一下,应该是没判断的话后面if中引用值就段错误
if(pRoot2->val==pRoot1->val) //了
{ //考虑节点相等,再考虑左右子树都相等就可
return HasSubtree(pRoot1->left,pRoot2->left)&&HasSubtree(pRoot1->right,pRoot2->right);
}
else
{ //该节点不行,分别访问左或者右子树,
return HasSubtree(pRoot1->left,pRoot2)||HasSubtree(pRoot1->right,pRoot2);
}
}
};
最后,好吧,测试用例A={8,8,7,9,2,#,#,#,#,4,7},B={8,9,2};没通过。
gdb调试了一下,发现在寻找第一个根节点的8的时候,就跳进了if判断句中,导致我的程序输出的是false,可是按照测试用例,完全可以再向下遍历下,就可找到,但程序没有,所以出错。
自己再修改了一段时间,还是有几个测试用例没通过。说明本身程序思路就有点问题。于是看了下书上的分析。
分析如下,主要通过两步:
一:寻找A树中节点的值与B树根节点值相同的点。
二:再判断在A中以此为根节点的子结构是否和B有同样的结构。
第一步的思想正好可以解决我之前遇到的根节点相同,就不向后遍历的问题。书中程序代码如下:
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};
class Solution {
public:
bool HasSubtree(TreeNode* pRoot1, TreeNode* pRoot2)
{
bool result=false;
if(pRoot1!=NULL&&pRoot2!=NULL)
{
if(pRoot2->val==pRoot1->val)
{
result=DoesTree1HaveTree2(pRoot1,pRoot2);
}
if(!result)
{
result=HasSubtree(pRoot1->left,pRoot2);
}
if(!result)
{
result=HasSubtree(pRoot1->right,pRoot2);
}
}
return result;
}
bool DoesTree1HaveTree2(TreeNode* pRoot1,TreeNode* pRoot2)
{
if(pRoot2==NULL) //此处如果是先判断pRoot1==NULL,return false,则不行,看来以后程序要从真的开始判断先。
return true;
if(pRoot1==NULL)
return false;
if(pRoot1->val!=pRoot2->val)
return false;
return DoesTree1HaveTree2(pRoot1->left,pRoot2->left)&&DoesTree1HaveTree2(pRoot1->right,pRoot2->right);
}
};
小结:
在写程序的时候,考虑到遍历,但是没有想到先遍历树查找到与子树根节点相同的值,再进行判断,我就直接一上来就判断,然后返回了。对于开始没有,没有完全遍历完二叉树,就返回了结果。
经常忘记判断节点是否为空。
还有,对于返回bool类型,先设一个bool型的临时变量,再程序中间做改变是一个好的习惯,尤其是bool型可能要经常改变。