剑指offer -- 树的子结构

题目:输入两棵二叉树A和B,判断B是不是A的子结构。二叉树结点定义如下

typedef struct Node{
	double val;
	BinaryTreeNode *left;
	BinaryTreeNode *right;
}BinaryTreeNode;

在这里插入图片描述
如上图中的两棵二叉树,A树(左边的二叉树)中有一部分子树的结构与B树一样(右边的二叉树)。因此B树是A树的子结构。

分析:
要查找树A中是否存在和树B结构一样的子树,我们可以分为两步,先在树A中找到和树B的根节点的值一样的结点R。再判断树A中以R为根节点的子树是不是包含和树B一样的结构。

以上面的两棵树为例来详细分析这个过程。首先试着在树A中找到值为8(树B的根节点的值)的节点。从树A的根节点开始遍历,我们发现它的根节点的值就是8。接着判断树A的根节点下面的子树是不是含有和树B一样的结构。在树A中,根节点的左子节点的值是8,而树B的根节点的左子节点是9,对应的两个节点不同。

因此我们仍然需要遍历树A,接着查找值为8的节点。我们在树的第二层中找到了一个值为8的节点,然后进行第二步判断,即判断这个节点下面的子树是否含有和树B一样的结构,于是我们遍历这个节点下面的子树,先后得到两个子节点9和2,这和树B的结构完全相同。此时我们在树A中找到了一棵和树B的结构一样的子树,因此树B是树A的子结构。

第一步在树中查找与根节点一样的节点 ,这实际上就是树的遍历,我们可以用递归的方法去遍历树A,找到一个与树B根节点值相等的节点就进入第二步。第二步是判断树A中以R为根节点的子树是不是和树B具有相同的结构。同样,我们也可以用递归的思路来考虑:如果节点R的值和树B的根节点不相同,则以R为根节点的子树和树B肯定不具有相同的节点;如果它们的值相同,则递归地判断它们各自的左右节点的值是不是相同。递归的终止条件是我们到达了树A或者树B的叶节点。如果到达了树B的叶节点,那证明前面遍历到的节点中的值都相等,返回true。如果在遍历过程中发现节点里的值不相等或者在树B还没有到达叶节点而树A却先到达了叶节点的时候,返回false。

还有一个细节需要我们注意,节点里面的数值是double类型,由于计算机表示小数(包括float和double型小数)都有误差,我们不能直接用等号(==)判断两个小数是否相等。如果两个小数的差的绝对值很小,如小于0.0000001,就可以认为它们相等。这就是下面equal函数的意义。

代码:

bool isSubStructure(BinaryTreeNode * A,BinaryTreeNode* B){
	bool result =false;
	
	if(A != NULL && B != NULL){
		if(equal(A->val , B->val)){      //二者值相等,进入第二步
			result = IsTreeAIncludeTreeB(A,B);
		}
		if(!result)                  //虽然找到了一个与树B根节点值相等的节点 但下面的结构并不符合
			result = isSubStructure(A->left,B);   //需要继续向下遍历找到 新的节点
		if(!result)
			result = isSubStructure(A->right,B);
	}
	return result;
}
bool IsTreeAIncludeTreeB(BinaryTreeNode* A, BinaryTreeNode* B){
	if(B == NULL)
		return true;
	if(A == NULL)  //避免试图访问空指针而造成崩溃 也设置了递归调用的退出条件
		return false;

	if(!equal(A->val, B->val))
		return false;

	return IsTreeAIncludeTreeB(A->left,B->left) && IsTreeAIncludeTreeB(A->right,B->right);
}
bool equal(double a,double b){
	if(a-b> -0.0000001 && a-b<0.0000001)
		return true;
	else
		return false;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值