题目链接地址:
题目描述:
输入两颗二叉树A,B,判断B是不是A的子结构。
输入:
输入可能包含多个测试样例,输入以EOF结束。
对于每个测试案例,输入的第一行一个整数n,m(1<=n<=1000,1<=m<=1000):n代表将要输入的二叉树A的节点个数(节点从1开始计数),m代表将要输入的二叉树B的节点个数(节点从1开始计数)。接下来一行有n个数,每个数代表A树中第i个元素的数值,接下来有n行,第一个数Ki代表第i个节点的子孩子个数,接下来有Ki个树,代表节点i子孩子节点标号。接下来m+1行,与树A描述相同。
输出:
对应每个测试案例,
若B是A的子树输出”YES”(不包含引号)。否则,输出“NO”(不包含引号)。
样例输入:
7 3
8 8 7 9 2 4 7
2 2 3
2 4 5
0
0
2 6 7
0
0
8 9 2
2 2 3
0
0
1 1
2
0
3
0
样例输出:
YES
NO
提示:
B为空树时不是任何树的子树。
解题思路:
(1)先构造二叉树A和二叉树B,因为二叉树是一种递归的数据结构,也就是说二叉树的子树也是二叉树,利用二叉树的这个性质。先将二叉树的每个结点都看成是只有根结点没有左右子树的二叉树,然后根据每个结点的左右孩子得出各个结点之间的父子关系,构造出二叉树的结构,再将没有父结点的结点挑出来做为二叉树的根结点,这样就完成了二叉树的构造;(需要注意的是题目并没有说明如何处理一个孩子结点的情况。我上网搜了一下,网上的说法是当输入1时,认为该结点只有一个左孩子结点,我想测试数据中可能没有孩子个数为1的数据吧)
(2)依次遍历二叉树A的每个结点rootA;(二叉树遍历的本质是将树形结构转化为线性结构,二叉树有前序遍历,中序遍历,后序遍历3种遍历方式。因为题目已经给出了二叉树A的结点数值数组,而在构造二叉树的过程中会用到结点数组,所以我采用遍历结点数组的办法来遍历二叉树A,具体请参看代码)
(3)将当前正在被遍历的二叉树A的结点rootA与二叉树B的根结点rootB进行比较,如果二者相等则同时前序遍历以rootA为根结点的二叉树subA和二叉树B。在前序遍历的过程中如果发现B树中的某些结点在subA树中不存在(如图1所示)或者B树中某个结点值与subA树中位置相同的结点值不相等(如图2所示),则可以断定B树不是subA树的子树,提前终止本次前序遍历过程,跳转到步骤(2)继续遍历二叉树A的下一个结点,直至二叉树A中的所有结点被遍历完为止。
图1 B树的结点2在subA树中不存在,可以断定B不是subA的子树
图2 B树的结点3与subA树中同位置的结点2不相等,可以断定B不是subA的子树
AC代码如下:
#include<stdio.h>
#define MAX 1002
// 定义二叉树的结点结构
typedef struct Node
{
bool isRootNode; // 标记结点是否为根结点
int data; // 数据域
Node * lChild; // 左孩子
Node * rChild; // 右孩子
}BinaryTreeNode;
BinaryTreeNode biTree[2][MAX]; // 定义二叉树的结点数组,BiTree[0][]表示二叉树A,BiTree[1][]表示二叉树B
bool ifBTreeIsSubOfATree; // 标记二叉树B是否为二叉树A的子树
/**
* 初始化二叉树的各个结点的关系,将每个结点都看成是一棵只包含根结点而没有左右子树的二叉树
* @param int numberOfNode 表示二叉树的结点个数
* @param int index index为0时,表示初始化的是二叉树A,index为1时,表示初始化的是二叉树B
* @return void
*/
void initBinaryTree(int numberOfNode,int index)
{
int i;
// 初始状态下认为每个结点都是一颗只包含根结点的二叉树
for(i = 1;i <= numberOfNode;i++)
{
scanf("%d",&biTree[index][i].data);
biTree[index][i].lChild = NULL;
biTree[index][i].rChild = NULL;
biTree[index][i].isRootNode = true;
}
}
/**
* 构造二叉树
* @param int numberOfNode 表示二叉树的结点个数
* @param int index index为0时,表示构造的是二叉树A,index为1时,表示构造的是二叉树B
* @return BinaryTreeNode * 返回二叉树的根结点
*/
BinaryTreeNode * createBinaryTree(int numberOfNode,int index)
{
BinaryTreeNode * root = NULL;
int i;
int numberOfChild; // 标记结点的孩子的个数
int lChild,rChild; // lChild为左孩子的结点编号,rChild为右孩子的结点编号
initBinaryTree(numberOfNode,index); // 初始化二叉树中的各个结点之间的关系
for(i = 1;i <= numberOfNode;i++)
{
scanf("%d",&numberOfChild);
switch(numberOfChild)
{
case 0:
break;
case 1: // 当输入1时,认为结点只有一个左孩子结点,网上搜来的,测试数据中没有孩子个数为1的情况
scanf("%d",&lChild);
biTree[index][i].lChild = &biTree[index][lChild];
biTree[index][lChild].isRootNode = false;
break;
case 2:
scanf("%d%d",&lChild,&rChild);
biTree[index][i].lChild = &biTree[index][lChild];
biTree[index][lChild].isRootNode = false;
biTree[index][i].rChild = &biTree[index][rChild];
biTree[index][rChild].isRootNode = false;
break;
default:
break;
}
}
// 寻找二叉树的根结点
for(i = 1;i <= numberOfNode;i++)
{
if(true == biTree[index][i].isRootNode)
{
root = &biTree[index][i];
break;
}
}
return root;
}
/**
* 先序遍历二叉树
* @param BinaryTreeNode * rootA 二叉树A的根结点
* @param BinaryTreeNode * rootB 二叉树B的根结点
* @return void
*/
void preOrderBinaryTree(BinaryTreeNode * rootA,BinaryTreeNode * rootB)
{
if(NULL == rootA || NULL == rootB)
{
//当B树中的结点不为空,而A树的结点为NULL时,表示B树中的部分结点不在A树中,所以可以认为B不是A的子树
if(NULL == rootA && NULL != rootB)
ifBTreeIsSubOfATree = false;
return;
}
else
{
if(rootA -> data == rootB -> data)
{
preOrderBinaryTree(rootA -> lChild,rootB -> lChild); // 先序遍历左子树
preOrderBinaryTree(rootA -> rChild,rootB -> rChild); // 先序遍历右子树
}
else
{
ifBTreeIsSubOfATree = false;
return; // 如果两个值不相同的结点,则立即返回,无需再进行后面的遍历操作
}
}
}
/**
* 判断二叉树B是否为二叉树A的子树
* @param BinaryTreeNode * rootA 二叉树A的根结点
* @param BinaryTreeNode * rootB 二叉树B的根结点
* @param int n 二叉树A的结点个数
* @param int m 二叉树B的结点个数
* @return 如果二叉树B是二叉树A的子树,则返回true;否则返回false
*/
bool isBTreeIsSubOfATree(BinaryTreeNode * rootA,BinaryTreeNode * rootB,int n,int m)
{
int i;
ifBTreeIsSubOfATree = false;
// 遍历A树中的每一个结点,如果结点值与B树根结点的值相等则采用先序遍历进行比较
for(i = 1;i <= n;i++)
{
if(biTree[0][i].data == rootB -> data)
{
ifBTreeIsSubOfATree = true;
preOrderBinaryTree(&biTree[0][i],rootB);
if(true == ifBTreeIsSubOfATree)
{
return true;
}
}
}
return ifBTreeIsSubOfATree;
}
int main()
{
int n,m;
BinaryTreeNode * rootA; // 二叉树A的根结点
BinaryTreeNode * rootB; // 二叉树B的根结点
while(EOF != scanf("%d%d",&n,&m))
{
rootA = createBinaryTree(n,0);
rootB = createBinaryTree(m,1);
if(NULL == rootA || NULL == rootB)
{
printf("NO\n");
}
else
{
ifBTreeIsSubOfATree = isBTreeIsSubOfATree(rootA,rootB,n,m);
if(true == ifBTreeIsSubOfATree)
{
printf("YES\n");
}
else
{
printf("NO\n");
}
}
}
return 0;
}
/**************************************************************
Problem: 1520
User: blueshell
Language: C++
Result: Accepted
Time:10 ms
Memory:1068 kb
****************************************************************/