题目:输入两棵二叉树 A 和 B,判断 B 是不是 A 的子结构。如图:
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指针,二叉树的所有节点都没有左子树或右子树)