【题目】输入两棵二叉树A和B,判断B是不是A的子结构。
【分析】
典型的二叉树问题。
判断两个二叉树的所属关系,其实还是要从二叉树的结构特点出发,二叉树由根节点和左右孩子构成,如果一个二叉树是另一个的子树,说明这个二叉树根节点,左右孩子必然存在于另一个二叉树中,例如:
观察上图,发现第二个二叉树明显是第一个二叉树的子结构,首先,看根节点,8,第一棵树根节点为8,等于第二棵二叉树,观察其左右孩子结构,如果一致,说明所属关系成立,但是根结点为8的第一棵二叉树左孩子是8,第二棵二叉树左节点却是9,所以继续查看观察的第一棵二叉树的左子树,左子树第一个根节点就是8,所以看它的左右孩子,左孩子是9,等于第二棵二叉树,所以再看右孩子,是2,结构完全相等,说明第二棵二叉树是第一棵二叉树的子结构成立。
在判断过程中,很明显用递归方法比较简单,递归判断二叉树A的根结点和二叉树B根节点是否相同,找到相同的后,再递归判断左右孩子结构是否一致。
【示例代码】
#include<stdio.h>
#include<stdlib.h>
#define false 0
#define true 1
typedef struct BinaryTreeNode
{
char data;
struct BinaryTreeNode *left;
struct BinaryTreeNode *right;
}Node;
//按照前序输入二叉树中结点的值
//构建二叉树
void create(Node **T)
{
char ch;
scanf("%c",&ch);
if(ch == '#')
*T = NULL;
else
{
*T = (Node *)malloc(sizeof(Node));
(*T)->data = ch;
create(&(*T)->left);
create(&(*T)->right);
}
}
bool doestree1havetree2(Node *root1, Node *root2)
{
if(root2 == NULL)
return true;
if(root1 == NULL)
return false;
if(root1->data != root2->data)
return false;
return doestree1havetree2(root1->left,root2->left) &&doestree1havetree2(root1->right, root2->right);
}
bool hassubtree(Node *root1, Node *root2)
{
bool result = false;
if(root1 != NULL && root2 != NULL)
{
if(root1 ->data == root2->data)
result = doestree1havetree2(root1,root2);
if(!result)
result = hassubtree(root1->left, root2);
if(!result)
result = hassubtree(root1->right, root2);
}
return result;
}
void main()
{
Node * root1 = NULL;
Node * root2 = NULL;
printf("二叉树1:\n");
create(&root1);
printf("\n");
printf("二叉树2:\n");
getchar();
create(&root2);
printf("\n");
printf("二叉树2是在二叉树1子构吗:\n");
bool r = hassubtree(root1, root2);
if(r == false)
printf("no, root2 is not root1's subtree!\n");
if(r == true)
printf("yes, root2 is root1's subtree!\n");
printf("\n");
}
【测试结果】
按照前序遍历创建二叉树1和2
在测试代码时,出现了问题,创建了二叉树1之后,二叉树2无法创建,究其原因是因为在创建链表过程中忽略了一个问题,在我们输入字符时都是先进入缓存区,scanf访问缓存得到数据,当我们把889##24##7##7##输完后输入回车,scanf读到回车符,就知道,输入完毕了,但是此时缓存区回车字符还在,当下一次输入89##2##时,先读取的是缓存区的回车符,然后才读89。。。这些数据,所以在建立树2时,清理缓存, getchar()清除缓冲区单一字符输入时scanf(“%c’,&a[i]);的换行符’\n’,除了getchar以外还有 fflush()是清除文件缓冲区,fflush(stdin); 如果没有这句,则stdio中还有数据,比如回车符,除此之外, scanf(“\n%d”,&c)也能达到效果,但不是清理缓存,而是自动将回车符读取了,scanf本来就是按照格式化的输入,所以当第一个输入为回车时它自动读取了,就不用清理缓存了。