《剑指Offer》面试题18:树的子结构
知识点
二叉树遍历算法和递归
题目描述
输入两课二叉树A和B,判断B是不是A的子结构。二叉树结点的定义如下:
解题思路
要查找树A中是否存在和树B结构一样的子树,我们可以分为两步:第一步在树A中找到和树B的根结点的值一样的结点R,第二步再判断树A中以R为根结点的子树是不是包含和B一样的结构。
通常我们都会采用递归的方式,但是这里需要注意的检查边界条件,即空指针。
测试用例
代码
// 《剑指Offer——名企面试官精讲典型编程题》代码
// 著作权所有者:何海涛
#include "stdio.h"
#include "cstdlib"
struct BinaryTreeNode
{
int m_nValue;
BinaryTreeNode *m_pLeft;
BinaryTreeNode *m_pRight;
};
BinaryTreeNode* CreateBinaryTreeNode(int value)
{
BinaryTreeNode* pNode = new BinaryTreeNode();
pNode->m_nValue = value;
pNode->m_pLeft = NULL;
pNode->m_pRight = NULL;
return pNode;
}
void ConnectTreeNodes(BinaryTreeNode* pParent, BinaryTreeNode* pLeft, BinaryTreeNode* pRight)
{
if (pParent != NULL)
{
pParent->m_pLeft = pLeft;
pParent->m_pRight = pRight;
}
}
void DestroyTree(BinaryTreeNode* pRoot)
{
if (pRoot != NULL)
{
BinaryTreeNode* pLeft = pRoot->m_pLeft;
BinaryTreeNode* pRight = pRoot->m_pRight;
delete pRoot;
pRoot = NULL;
DestroyTree(pLeft);
DestroyTree(pRight);
}
}
bool HasSubtree(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2);
bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2);
bool HasSubtree(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
bool result = false;
if (pRoot1 != NULL && pRoot2 != NULL)
{
if (pRoot1->m_nValue == pRoot2->m_nValue)
result = DoesTree1HaveTree2(pRoot1, pRoot2);
if (!result)
result = HasSubtree(pRoot1->m_pLeft, pRoot2);
if (!result)
result = HasSubtree(pRoot1->m_pRight, pRoot2);
}
return result;
}
bool DoesTree1HaveTree2(BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2)
{
if (pRoot2 == NULL)
return true;
if (pRoot1 == NULL)
return false;
if (pRoot1->m_nValue != pRoot2->m_nValue)
return false;
return DoesTree1HaveTree2(pRoot1->m_pLeft, pRoot2->m_pLeft) &&
DoesTree1HaveTree2(pRoot1->m_pRight, pRoot2->m_pRight);
}
// ====================测试代码====================
void Test(char* testName, BinaryTreeNode* pRoot1, BinaryTreeNode* pRoot2, bool expected)
{
if (HasSubtree(pRoot1, pRoot2) == expected)
printf("%s passed.\n", testName);
else
printf("%s failed.\n", testName);
}
// 树中结点含有分叉,树B是树A的子结构
// 8 8
// / \ / \
// 8 7 9 2
// / \
// 9 2
// / \
// 4 7
void Test1()
{
BinaryTreeNode* pNodeA1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA2 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA3 = CreateBinaryTreeNode(7);
BinaryTreeNode* pNodeA4 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeA5 = CreateBinaryTreeNode(2);
BinaryTreeNode* pNodeA6 = CreateBinaryTreeNode(4);
BinaryTreeNode* pNodeA7 = CreateBinaryTreeNode(7);
ConnectTreeNodes(pNodeA1, pNodeA2, pNodeA3);
ConnectTreeNodes(pNodeA2, pNodeA4, pNodeA5);
ConnectTreeNodes(pNodeA5, pNodeA6, pNodeA7);
BinaryTreeNode* pNodeB1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeB2 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeB3 = CreateBinaryTreeNode(2);
ConnectTreeNodes(pNodeB1, pNodeB2, pNodeB3);
Test("Test1", pNodeA1, pNodeB1, true);
DestroyTree(pNodeA1);
DestroyTree(pNodeB1);
}
// 树中结点含有分叉,树B不是树A的子结构
// 8 8
// / \ / \
// 8 7 9 2
// / \
// 9 3
// / \
// 4 7
void Test2()
{
BinaryTreeNode* pNodeA1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA2 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA3 = CreateBinaryTreeNode(7);
BinaryTreeNode* pNodeA4 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeA5 = CreateBinaryTreeNode(3);
BinaryTreeNode* pNodeA6 = CreateBinaryTreeNode(4);
BinaryTreeNode* pNodeA7 = CreateBinaryTreeNode(7);
ConnectTreeNodes(pNodeA1, pNodeA2, pNodeA3);
ConnectTreeNodes(pNodeA2, pNodeA4, pNodeA5);
ConnectTreeNodes(pNodeA5, pNodeA6, pNodeA7);
BinaryTreeNode* pNodeB1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeB2 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeB3 = CreateBinaryTreeNode(2);
ConnectTreeNodes(pNodeB1, pNodeB2, pNodeB3);
Test("Test2", pNodeA1, pNodeB1, false);
DestroyTree(pNodeA1);
DestroyTree(pNodeB1);
}
// 树中结点只有左子结点,树B是树A的子结构
// 8 8
// / /
// 8 9
// / /
// 9 2
// /
// 2
// /
// 5
void Test3()
{
BinaryTreeNode* pNodeA1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA2 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA3 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeA4 = CreateBinaryTreeNode(2);
BinaryTreeNode* pNodeA5 = CreateBinaryTreeNode(5);
ConnectTreeNodes(pNodeA1, pNodeA2, NULL);
ConnectTreeNodes(pNodeA2, pNodeA3, NULL);
ConnectTreeNodes(pNodeA3, pNodeA4, NULL);
ConnectTreeNodes(pNodeA4, pNodeA5, NULL);
BinaryTreeNode* pNodeB1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeB2 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeB3 = CreateBinaryTreeNode(2);
ConnectTreeNodes(pNodeB1, pNodeB2, NULL);
ConnectTreeNodes(pNodeB2, pNodeB3, NULL);
Test("Test3", pNodeA1, pNodeB1, true);
DestroyTree(pNodeA1);
DestroyTree(pNodeB1);
}
// 树中结点只有左子结点,树B不是树A的子结构
// 8 8
// / /
// 8 9
// / /
// 9 3
// /
// 2
// /
// 5
void Test4()
{
BinaryTreeNode* pNodeA1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA2 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA3 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeA4 = CreateBinaryTreeNode(2);
BinaryTreeNode* pNodeA5 = CreateBinaryTreeNode(5);
ConnectTreeNodes(pNodeA1, pNodeA2, NULL);
ConnectTreeNodes(pNodeA2, pNodeA3, NULL);
ConnectTreeNodes(pNodeA3, pNodeA4, NULL);
ConnectTreeNodes(pNodeA4, pNodeA5, NULL);
BinaryTreeNode* pNodeB1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeB2 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeB3 = CreateBinaryTreeNode(3);
ConnectTreeNodes(pNodeB1, pNodeB2, NULL);
ConnectTreeNodes(pNodeB2, pNodeB3, NULL);
Test("Test4", pNodeA1, pNodeB1, false);
DestroyTree(pNodeA1);
DestroyTree(pNodeB1);
}
// 树中结点只有右子结点,树B是树A的子结构
// 8 8
// \ \
// 8 9
// \ \
// 9 2
// \
// 2
// \
// 5
void Test5()
{
BinaryTreeNode* pNodeA1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA2 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA3 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeA4 = CreateBinaryTreeNode(2);
BinaryTreeNode* pNodeA5 = CreateBinaryTreeNode(5);
ConnectTreeNodes(pNodeA1, NULL, pNodeA2);
ConnectTreeNodes(pNodeA2, NULL, pNodeA3);
ConnectTreeNodes(pNodeA3, NULL, pNodeA4);
ConnectTreeNodes(pNodeA4, NULL, pNodeA5);
BinaryTreeNode* pNodeB1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeB2 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeB3 = CreateBinaryTreeNode(2);
ConnectTreeNodes(pNodeB1, NULL, pNodeB2);
ConnectTreeNodes(pNodeB2, NULL, pNodeB3);
Test("Test5", pNodeA1, pNodeB1, true);
DestroyTree(pNodeA1);
DestroyTree(pNodeB1);
}
// 树A中结点只有右子结点,树B不是树A的子结构
// 8 8
// \ \
// 8 9
// \ / \
// 9 3 2
// \
// 2
// \
// 5
void Test6()
{
BinaryTreeNode* pNodeA1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA2 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA3 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeA4 = CreateBinaryTreeNode(2);
BinaryTreeNode* pNodeA5 = CreateBinaryTreeNode(5);
ConnectTreeNodes(pNodeA1, NULL, pNodeA2);
ConnectTreeNodes(pNodeA2, NULL, pNodeA3);
ConnectTreeNodes(pNodeA3, NULL, pNodeA4);
ConnectTreeNodes(pNodeA4, NULL, pNodeA5);
BinaryTreeNode* pNodeB1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeB2 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeB3 = CreateBinaryTreeNode(3);
BinaryTreeNode* pNodeB4 = CreateBinaryTreeNode(2);
ConnectTreeNodes(pNodeB1, NULL, pNodeB2);
ConnectTreeNodes(pNodeB2, pNodeB3, pNodeB4);
Test("Test6", pNodeA1, pNodeB1, false);
DestroyTree(pNodeA1);
DestroyTree(pNodeB1);
}
// 树A为空树
void Test7()
{
BinaryTreeNode* pNodeB1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeB2 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeB3 = CreateBinaryTreeNode(3);
BinaryTreeNode* pNodeB4 = CreateBinaryTreeNode(2);
ConnectTreeNodes(pNodeB1, NULL, pNodeB2);
ConnectTreeNodes(pNodeB2, pNodeB3, pNodeB4);
Test("Test7", NULL, pNodeB1, false);
DestroyTree(pNodeB1);
}
// 树B为空树
void Test8()
{
BinaryTreeNode* pNodeA1 = CreateBinaryTreeNode(8);
BinaryTreeNode* pNodeA2 = CreateBinaryTreeNode(9);
BinaryTreeNode* pNodeA3 = CreateBinaryTreeNode(3);
BinaryTreeNode* pNodeA4 = CreateBinaryTreeNode(2);
ConnectTreeNodes(pNodeA1, NULL, pNodeA2);
ConnectTreeNodes(pNodeA2, pNodeA3, pNodeA4);
Test("Test8", pNodeA1, NULL, false);
DestroyTree(pNodeA1);
}
// 树A和树B都为空
void Test9()
{
Test("Test9", NULL, NULL, false);
}
int main()
{
Test1();
Test2();
Test3();
Test4();
Test5();
Test6();
Test7();
Test8();
Test9();
system("pause");
return 0;
}