树的子结构

判断二叉树子结构

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

104738_VhiY_2260265.jpg

                                                    A                                                                        B

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

以上面的两棵树为例,首先在树 A 中找到值为 8 (树 B的根节点的值) 的节点。从树 A的根节点开始遍历,发现根节点的值就是 8,接着去判断树 A 的根节点下面的子树是否含有与树 B 相同的结构。在树 A 中,根节点的左孩子为 8,而树 B 的根节点的左孩子为 9,对应的两个节点不同。因此,仍然需要遍历树 A,继续查找节点值为 8 的节点,然后再进行判断。

    第一步在树 A 中查找与根节点的值一样的节点,这实际上就是树的遍历。可以使用递归的方法进行遍历。注意边界条件的检查,即检查空指针。当树 A 和树 B 为空时,应该给出相应的输出。

    第二步是判断 A 中以 R 为根节点的子树是不是和树 B 具有相同的结构。同样可以使用递归的思路来考虑:如果节点 R 的值和树 B 的根节点相同,则以 R 为根节点的子树和树 B 肯定不具有相同的节点:如果它们的值相同,则递归地判断它们各自的左右节点的值是不是相同。递归的终止条件是到达了树 A 或者是树 B的叶节点。

 

//判断树 A 中是否含有子树 B
#include<iostream>
using namespace std;

typedef int ElemType;
typedef struct TNode
{
 ElemType value;
 struct TNode *LeftChild;
 struct TNode *RightChild;
}TreeNode, *BinaryTree;

//创建一棵二叉查找树
TreeNode* CreateBinaryTree(BinaryTree T, ElemType e)
{
 if(T == NULL)
 {
  T = new TreeNode();
  T->value = e;
  T->LeftChild = NULL;
  T->RightChild = NULL;
 }
 else
 {
  if(T->value > e)
   T->LeftChild = CreateBinaryTree(T->LeftChild, e);
  else if(T->value < e)
   T->RightChild = CreateBinaryTree(T->RightChild, e);
 }
 return T;    //返回根节点
}

//创建一个普通的二叉树
TreeNode* CreateTreeNode(ElemType e)
{
 TreeNode *T = new TreeNode();
 T->value = e;
 T->LeftChild = NULL;
 T->RightChild = NULL;
 return T;
}
void ConnectTreeNode(TreeNode *pParent, TreeNode *pLeft, TreeNode *pRight)
{
 if(pParent != NULL)
 {
  pParent->LeftChild = pLeft;
  pParent->RightChild = pRight;
 }
}

bool DoesTreeHaveSubTree(BinaryTree T1, BinaryTree T2)
{
 if(T2 == NULL)
  return true;
 if(T1 == NULL)
  return false;
 if(T1->value != T2->value)
  return false;

 return DoesTreeHaveSubTree(T1->LeftChild, T2->LeftChild) &&
  DoesTreeHaveSubTree(T1->RightChild, T2->RightChild);
}

bool HasSubTree(BinaryTree T1, BinaryTree T2)
{
 bool result = false;
 if(T1 != NULL && T2 != NULL)
 {
  if(T1->value == T2->value)
   result = DoesTreeHaveSubTree(T1, T2);
  if(!result)
   result = HasSubTree(T1->LeftChild, T2);
  if(!result)
   result = HasSubTree(T1->RightChild, T2);
 }
 return result;
}

int main()
{
 /*
 test1:  T1:      8                   T2:      4
                    / \                            / \
                  4   9                          3   6
                 / \   \
                3   6  10
              /
            2  
  
 */
 //TreeNode *T1 = NULL;
 //TreeNode *T2 = NULL;
 /*T1 = CreateBinaryTree(T1, 8);
 T1 = CreateBinaryTree(T1, 4);
 T1 = CreateBinaryTree(T1, 9);
 T1 = CreateBinaryTree(T1, 10);
 T1 = CreateBinaryTree(T1, 3);
 T1 = CreateBinaryTree(T1, 6);
 T1 = CreateBinaryTree(T1, 2);

 T2 = CreateBinaryTree(T2, 4);
 T2 = CreateBinaryTree(T2, 3);
 T2 = CreateBinaryTree(T2, 6);
 */

 /*
 test2:  T1:              8            T2:                  8
                             / \                                / \
                            8   7                             9   2
                           / \
                          9   2
                              / \
                             4   7
  
 */

 TreeNode *T1Node1 = CreateTreeNode(8);
 TreeNode *T1Node2 = CreateTreeNode(8);
 TreeNode *T1Node3 = CreateTreeNode(7);
 TreeNode *T1Node4 = CreateTreeNode(9);
 TreeNode *T1Node5 = CreateTreeNode(2);
 TreeNode *T1Node6 = CreateTreeNode(4);
 TreeNode *T1Node7 = CreateTreeNode(7);

 ConnectTreeNode(T1Node1, T1Node2, T1Node3);
 ConnectTreeNode(T1Node2, T1Node4, T1Node5);
 ConnectTreeNode(T1Node5, T1Node6, T1Node7);

 TreeNode *T2Node1 = CreateTreeNode(8);
 TreeNode *T2Node2 = CreateTreeNode(3);
 TreeNode *T2Node3 = CreateTreeNode(2);

 ConnectTreeNode(T2Node1, T2Node2, T2Node3);

 bool result = HasSubTree(T1Node1, T2Node2);
 cout << result << endl;

 system("pause");
 return 0;
}

 测试用例:1)功能测试(树 A 和 树 B 都是普通的二叉树,树 B 是或者不是树 A 的子结构)

                2) 特殊输入测试(两棵二叉树的一个或者两个根节点为 NULL指针,二叉树的所有节点都没有左子树或右子树)

 

 

 

转载于:https://my.oschina.net/u/2260265/blog/343865

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值