pta树的同构与列出叶结点(详解)

目录

 

树的同构

首先上思路大致思路:先找到该树的根节点,然后顺着根节点下去,到达的每一个节点的时候,所在的那一层进行比较,之后开始比较给节点的左右孩子,像深搜一样。

详解见代码

列出叶结点

 这题我看网上,其他人基本上都是用bfs写的,这题我没用,收到了上题的启发,这是我自己写的,写的比较简单,好理解,也能是因为数据比较小,所以就能水过去


树的同构

给定两棵树T1和T2。如果T1可以通过若干次左右孩子互换就变成T2,则我们称两棵树是“同构”的。例如图1给出的两棵树就是同构的,因为我们把其中一棵树的结点A、B、G的左右孩子互换后,就得到另外一棵树。而图2就不是同构的。

图1

图2

现给定两棵树,请你判断它们是否是同构的。

输入格式:

输入给出2棵二叉树树的信息。对于每棵树,首先在一行中给出一个非负整数N (≤10),即该树的结点数(此时假设结点从0到N−1编号);随后N行,第i行对应编号第i个结点,给出该结点中存储的1个英文大写字母、其左孩子结点的编号、右孩子结点的编号。如果孩子结点为空,则在相应位置上给出“-”。给出的数据间用一个空格分隔。注意:题目保证每个结点中存储的字母是不同的。

输出格式:

如果两棵树是同构的,输出“Yes”,否则输出“No”。

输入样例1(对应图1):

8
A 1 2
B 3 4
C 5 -
D - -
E 6 -
G 7 -
F - -
H - -
8
G - 4
B 7 6
F - -
A 5 1
H - -
C 0 -
D - -
E 2 -

输出样例1:

Yes

输入样例2(对应图2):

8
B 5 7
F - -
A 0 3
C 6 -
H - -
D - -
G 4 -
E 1 -
8
D 6 -
B 5 -
E - -
H - -
C 0 2
G - 3
F - -
A 1 4

输出样例2:

No

首先上思路大致思路:先找到该树的根节点,然后顺着根节点下去,到达的每一个节点的时候,所在的那一层进行比较,之后开始比较给节点的左右孩子,像深搜一样。

详解见代码

#include<bits/stdc++.h>
using namespace std;
#define NULL -1
struct node
{
    char ch;
    int left;
    int right;
} tree1[100],tree2[100];//创建两个树
bool book[100];

int build(node tree[])//建树,并返回根节点
{
    int n;
    int book[110];
    char data,l,r;
    memset(book,0,sizeof(book));
    scanf("%d",&n);
    for(int i=0; i<n; i++)
    {
        getchar();
        //第i个节点对应的值
        scanf("%c",&data);
        getchar();
        //左孩子
        scanf("%c",&l);
        getchar();
        //右孩子
        scanf("%c",&r);
        tree[i].ch = data;
        if(l == '-')
            tree[i].left = NULL;
        else
        {
            tree[i].left = l-'0';//孩子节点对应的序号
            book[l-'0'] = 1;//记录他是别人的子节点
        }
        if(r =='-')
            tree[i].right = NULL;
        else
        {
            tree[i].right = r-'0';
            book[r-'0'] = 1;
        }
    }
    int root = NULL;//很可能整个树是个空的
    //寻找不是别人的孩子的节点,即根节点
    for(int i=0; i<n; i++)
    {
        if(!book[i])
        {
            root = i;
        }
    }
    return root;//返回根节点的序号
}
bool judge(int root1,int root2)
{
    if(root1==NULL&&root2==NULL)return 1;//如果两个都是空树
    //两个树其中一个是空树,一个不是
    if(root1==NULL&&root2!=NULL||root1!=NULL&&root2==NULL)
        return 0;
    //判断该节点的值是否相同,不明白,可以从根节点开始向下考虑
    if(tree1[root1].ch!=tree2[root2].ch)
        return 0;
    //判断此树的左右孩子是否相等
    if(tree1[tree1[root1].left].ch==tree2[tree2[root2].left].ch)
        return judge(tree1[root1].right,tree2[root2].right);
    else
    {
        //不相同,调换位置比较
        return judge(tree1[root1].left,tree2[root2].right)&&
               judge(tree1[root1].right,tree2[root2].left);
    }

}

int main()
{
    int root1 = build(tree1);
    int root2 = build(tree2);
    if(judge(root1,root2)==1)
    {
        printf("Yes\n");
    }
    else
    {
        printf("No\n");
    }
    return 0;

}

列出叶结点

对于给定的二叉树,本题要求你按从上到下、从左到右的顺序输出其所有叶节点。

输入格式:

首先第一行给出一个正整数 N(≤10),为树中结点总数。树中的结点从 0 到 N−1 编号。随后 N 行,每行给出一个对应结点左右孩子的编号。如果某个孩子不存在,则在对应位置给出 "-"。编号间以 1 个空格分隔。

输出格式:

在一行中按规定顺序输出叶节点的编号。编号间以 1 个空格分隔,行首尾不得有多余空格。

输入样例:

8
1 -
- -
0 -
2 7
- -
- -
5 -
4 6

输出样例:

4 1 5

 这题我看网上,其他人基本上都是用bfs写的,这题我没用,收到了上题的启发,这是我自己写的,写的比较简单,好理解,也能是因为数据比较小,所以就能水过去

思路:找到叶节点,并且叶节点附带深度,由于该题是从左到右,从上到下,左到右可以先访问左孩子再访问右孩子,上到下可以深度着手,深度越浅先输出,越深后输出,当然这里的深度不是什么神奇的东西,很简单的一个东西。在我的代码我用的是cen来代表,当时考虑的是层数,哈哈,应该是深度。巨详解如下:

#include<bits/stdc++.h>
using namespace std;
#define NULL -1
struct node
{
    int  ch;
    int left;
    int right;
    int cen;//层数
} tree1[100],tree2[100];
//选出来的叶节点
struct nnode
{
    int ch;
    int cen;//层数
}ans[100];
bool book[100];
int anscount = 0;
//这一步找到根节点
int build(node tree[])
{
    int n;
    int book[110];
    char l,r;
    memset(book,0,sizeof(book));
    scanf("%d",&n);
    for(int i=0; i<n; i++)
    {
        tree[i].cen = 0;
        tree[i].ch = i;
        getchar();
        scanf("%c",&l);
        getchar();
        scanf("%c",&r);
        if(l == '-')
            tree[i].left = NULL;
        else
        {
            tree[i].left = l-'0';
            book[l-'0'] = 1;
        }
        if(r =='-')
            tree[i].right = NULL;
        else
        {
            tree[i].right = r-'0';
            book[r-'0'] = 1;
        }
    }
    int root = NULL;
    for(int i=0; i<n; i++)
    {
        if(!book[i])
        {
            root = i;
        }
    }
    return root;
}
//这一步是找到叶节点
void found(int root)
{
    //如果它是叶节点就被记录下来
    if(tree1[root].left==NULL&&tree1[root].right==NULL){
       ans[anscount].ch = tree1[root].ch;//记录值
       ans[anscount++].cen = tree1[root].cen;//记录层数
       // printf("%d",tree1[root].ch);
        return;
    }
    //如果存在左孩子,进行访问
    if(tree1[root].left!=NULL){
        //左孩子的层数是他爸爸层数+1
        tree1[tree1[root].left].cen = tree1[root].cen+1;
        /*cout<<tree1[root].cen<<"--";
        cout<<tree1[tree1[root].left].ch<<"--"<<tree1[tree1[root].left].cen;
        cout<<endl;*/
        found(tree1[root].left);//继续向下访问
    }
    //如果存在右孩子,进行访问
    if(tree1[root].right!=NULL){
        //右孩子的层数是他爸爸层数+1
        tree1[tree1[root].right].cen = tree1[root].cen+1;
        found(tree1[root].right);
    }

}


int main()
{
    int root1 = build(tree1);
    found(root1);
    int cnt = 0;
    for(int i=0;i<=10;i++){//i代表层数,因为这题最大只有10,所以这是个空子
        for(int j=0;j<anscount;j++){
            if(ans[j].cen == i )//小层数的先输出来
            {
                //printf("--%d--",i);
                if(cnt) printf(" ");//这个是用来防止最后一位有空格的
                cnt++;
                printf("%d",ans[j].ch);
            }
        }
    }
    return 0;

}
原创文章 96 获赞 28 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_43813140/article/details/105397725