PAT 数据结构 03-树1 树的同构 (25 分)

题目描述:

实现代码及解释(注释部分): 

 

#include<stdio.h>
#include<stdlib.h>
#define MaxTree 10
#define Null -1

typedef char ElementType;
typedef int Tree;
typedef struct TNode{
    ElementType Data;
    Tree Left;
    Tree Right;
}TNode;
typedef TNode *PtrToTNode;
TNode T1[MaxTree],T2[MaxTree];

Tree BuildTree(TNode T[])
//在数组的空间里面建立链接,形成树
//树,线性表的核心都是建立一种逻辑关系,在一段空间里建立一种逻辑关系,并把有这些有逻辑关系的数据链接起来
{
    int root=-1;
    int n;
    char cl,cr;
    scanf("%d",&n);
    int check[n];//可变数组
    if(n){
    for(int i=0;i<n;i++)
    check[i]=0;
    for(int i=0;i<n;i++){
        scanf("\n%c %c %c",&T[i].Data,&cl,&cr);//这里这个\n的作用非常巨大。而且也非常容易被忽视!!!
        /*因为这用的是scanf函数进行输入,scanf会自动跳过前面的空白,直到找到第一个想要输入的数据类型,这样子看似很方便,但是也很容易被忽视,此处的第一个
        想要输入的类型是char,而上一次输入结束后,会在缓冲区里留下一个\n字符,所以这个第一次读取时,就把\n读取进了T[i].Data,所以没能读取到后面想要读取的字符,所以要处理掉上一次输入留下的\n
        这里利用scanf格式化输入的特性,在前面加上\n就可以处理掉这个/n。或者用getchar()消化掉这个\n字符*/
        if(cl!='-'){
            T[i].Left=cl-'0';
            check[T[i].Left]=1;
        }
        else
        T[i].Left=Null;
        if(cr!='-'){
            T[i].Right=cr-'0';
            check[T[i].Right]=1;
        }
        else
        T[i].Right=Null;
    }
    //确定树根
    for(int i=0;i<n;i++)
    if(check[i]==0){
        root=i;
        break;
    }
    }
    return root;
}

int Isomorphic(Tree R1,Tree R2)
/*判断两棵树是否同构,因为树是同归递归定义的,所以我们很自然的可能就会想到通过递归判断树是否同构,即递归的判断根的子树是否同构
判断树是否同构有以下几种情况:
1:两树均为空树时,我们认为是同构的-->return 1;
2:一棵树为空,一棵树不空,两树不同构-->return 0;
3:两棵树均不空,但是两树的根的键值(关键值)不同,显然这两棵树也是不同构的-->return 0;
4:两棵树的左子树均为空树时,显然只需要判断两树的右子树是否同构即可。-->return (Isomorphic(R1->left,R2->left))
5:两颗树的左子树均不空时,并且两树的左子树的键值相同时,显然需要判断其做左子树是否同构,还要判断其右子树是否同构
6:剩下的所有情况都可以归为判断其左子树与另一棵树的右子树是否同构,其右子树与另一棵树的左子树是否同构

进一步解释:
其实情况五包含了多种情况,左子树均不空且左子树的键值相等时,显然时两颗树的左子树与左子树判断,而此时我们不需要去考虑右子树的情况,因为右子树的情况在对右子树调用Isomorphic函数
判断是否同构时会对右子树存在与否的各种情况进行判断。而如果没有满足条件五的情况,那就说明,可能时一棵树有左子树,一棵树没有左子树,那么这种情况想要
两棵树同构,就只能对左子树和右子树判断是否同构,还有可能时两个左子树均不空,但是两个左子树的键值不等,那就和上面的情况一样了,只能对左子树和右子树进行判断
是否同构,因为根键值不等,这两颗树肯定不同构
条件四其实也包含了比较多种情况,显然的就是,左子树均空时,其右子树会存在多种情况,比如右子树均空,一个空,均不空....但是右子树的情况不需要我们去考虑,因为
在调用Isomorphic函数的时候,会对这些情况进行判断。
*/
{
    if((R1==Null)&&(R2==Null))
    return 1;
    if(((R1==Null)&&(R2!=Null))||((R1!=Null)&&(R2==Null)))
    return 0;
    if(T1[R1].Data!=T2[R2].Data)
    return 0;
    if((T1[R1].Left==Null)&&(T2[R2].Left==Null))
    return Isomorphic(T1[R1].Right,T2[R2].Right);
    if(((T1[R1].Left!=Null)&&(T2[R2].Left!=Null))&&((T1[T1[R1].Left].Data)==(T2[T2[R2].Left].Data)))
    return (Isomorphic(T1[R1].Left,T2[R2].Left))&&(Isomorphic(T1[R1].Right,T2[R2].Right));
    else
    return (Isomorphic(T1[R1].Left,T2[R2].Right)&&Isomorphic(T1[R1].Right,T2[R2].Left));
}

int main(void)
{
    Tree R1,R2;
    R1=BuildTree(T1);
    R2=BuildTree(T2);
    if(Isomorphic(R1,R2))
    printf("Yes");
    else
    printf("No");
    system("pause");
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值