ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

binary tree+tree order

2022-08-11 22:30:11  阅读:153  来源: 互联网

标签:node binary 后序 int 中序 tree 序列 root order


二叉树的前中序确定后序:http://acm.hdu.edu.cn/showproblem.php?pid=1710

二叉树的后中序确定层序:https://pintia.cn/problem-sets/994805342720868352/problems/994805485033603072

二叉树的前中序确定后序变形:https://pintia.cn/problem-sets/994805342720868352/problems/994805380754817024

二叉树反转:https://pintia.cn/problem-sets/994805342720868352/problems/994805365537882112

二叉树遍历dfs:https://pintia.cn/problem-sets/994805342720868352/problems/994805388447170560

二叉树遍历dfs:https://pintia.cn/problem-sets/994805342720868352/problems/994805376476626944

二叉树遍历dfs:https://pintia.cn/problem-sets/994805342720868352/problems/994805362341822464

二叉树遍历bfs:https://pintia.cn/problem-sets/994805342720868352/problems/994805376476626944

 

1.二叉树中前序确定后序:

其实这个已经说过了,为了加深一下印象又做了一次;

前中序确定后序其实还是很简单的,

 

 

 和上图所化差不多,从先序序列开始,依次在中序序列中找到相应位置,相应位置的左边就是左子树,右边是右子树,挨个遍历,直到把先序序列遍历完或者是把二叉树建树完成就可以了

而本题所说的是根据先序序列和中序序列确定后序序列,这样在进行一次后序遍历就可以了;

参考代码如下

// Problem: Binary Tree Traversals
// Contest: HDOJ
// URL: http://acm.hdu.edu.cn/showproblem.php?pid=1710
// Memory Limit: 32 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include<bits/stdc++.h>//hudoj 1710
using namespace std;
#define int long long
#define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
const int N=1010;
int k;//统计个数
int n;
int pre[N];//前序序列
int in[N];//中序序列
int post[N];//后序序列
struct node {
    int value;
    node *L;
    node *R;
    node(int value=0,node *L=NULL,node *R=NULL):value(value),L(L),R(R) {} //初始化
};
void buildtree(int L,int R,int &t,node * &root) { //建树,左子树,右子树,前序序列值的推进,根节点
    int flag=-1;
    for(register int i=L; i<=R; i++) {
        if(in[i]==pre[t]) { //找到了线序序列的位置
            flag=i;//对应中序序列的位置
            break;
        }
    }
    if(flag==-1)//没有就返回
        return ;
    root=new node(in[flag]);//新建子根节点
    if(flag>L) { //如果是在左子树上,那中序序列遍历的根节点左边在左子树上
        buildtree(L,flag-1,++t,root->L);
    }
    if(flag<R) { //如果是在右子树上,那中序序列遍历的根据二点右边在柚子树上,右子树需从i+1进行计数
        buildtree(flag+1,R,++t,root->R);
    }
}
void preorder(node *root) { //前序遍历
    if(root!=NULL) {
        post[k++]=root->value;
        preorder(root->L);
        preorder(root->R);
    }
}
void inorder(node *root) { //中序遍历
    if(root!=NULL) {
        inorder(root->L);
        post[k++]=root->value;
        inorder(root->R);
    }
}
void postorder(node *root) { //后序遍历
    if(root!=NULL) {
        postorder(root->L);
        postorder(root->R);
        post[k++]=root->value;
    }
}
void remove_tree(node *root) { //删除节点释放空间
    if(root==NULL)
        return ;
    remove_tree(root->L);
    remove_tree(root->R);
    delete root;
}
signed main() {
    IOS;
    while(cin>>n) {
        for(register int i=1; i<=n; i++)
            cin>>pre[i];
        for(register int i=1; i<=n; i++)
            cin>>in[i];
        int t=1;//同步前序序列,确定根节点
        node *root;
        buildtree(1,n,t,root);//建树
        k=0;
        postorder(root);//后序遍历
        for(register int i=0; i<k; i++) {
            printf("%d%c",post[i],i==k-1?'\n':' ');//输出
        }
        remove_tree(root);//释放空间
    }
    return 0;
}

2.根据后序和中序序列确定层序序列

这道题和上面那道题的不同之处在于建树的过程

因为如果按照上面建树过程的话其实你会发现给定的两个序列到了一定深度就会return ,而得到的层序序列是4,2,5,因为这个结果我试验过,并且手动debug了一下就是会在某个数字造成return而建树会被构造成一个单支树

怎么建树是本题的关键;

可以这样想:

后序序列的最后一个元素将会是根节点

所以我们在建树的时候要让根节点的键值等于后序序列的右边界

然后很常规的查找在中序序列中哪个是后序序列的右边界的元素的下标;

7
2 3 1 5 7 6 4
1 2 3 4 5 6 7

比如这组样例,下标为4的中序序列和后序序列的右边界相等,标为flag

那么他左子树的数量就是num=flag-inl(inl代表中序序列的左边界)

那遍历左子树的时候就可以这样写了(postl,postl+num-1,inl,flag-1)//后序左边界,后序右边界,中序左边界,中序右边界

遍历右子树的时候就可以(postl+num,postr-1,flag+1,inr)//后序左边界,后序右边界,中序左边界,中序右边界

和上面那道题不一样的建树过程是return 的条件变了,变成了当后序序列推进完成的时候就结束了

还有就是建树方式变成了由后序边界和中序边界共同确定的建树算法

上面的是只有中序边界和正序推进先序序列

但思想上的基本规则还是不变的,可以和上面那道题进行对比;

参考代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
 5 const int N=100;
 6 int n;
 7 int k;
 8 struct node
 9 {
10     int value;
11     node *l;
12     node *r;
13     node(int value=0,node *l=NULL,node *r=NULL):value(value),l(l),r(r){}
14 };
15 int post[N];
16 int in[N];
17 node *buildtree(int postl,int postr,int inl,int inr)
18 {
19     if(postr-postl<0)
20     return NULL;
21     node *root=new node(post[postr]);
22     int flag=-1;
23     for(int i=inl;i<=inr;i++)
24     {
25         if(in[i]==post[postr])
26         {
27             flag=i;
28             break;
29         }
30     }
31     int numl=flag-inl;
32     root->l=buildtree(postl,postl+numl-1,inl,flag-1);
33     root->r=buildtree(postl+numl,postr-1,flag+1,inr);
34     return root;
35 
36 }
37 void bfs(node *root)
38 {
39     queue<node *>q;
40     q.push(root);
41     while(!q.empty())
42     {
43         node *newnode=q.front();
44         q.pop();
45         cout<<newnode->value;
46         k++;
47         if(k<n)
48         cout<<" ";
49         if(newnode->l!=NULL)
50         q.push(newnode->l);
51         if(newnode->r!=NULL)
52         q.push(newnode->r);
53     }
54 }
55 signed main()
56 {
57     IOS;
58     cin>>n;
59     for(int i=1;i<=n;i++)
60     cin>>post[i];
61     for(int i=1;i<=n;i++)
62     cin>>in[i];
63     node *root=buildtree(1,n,1,n);
64     bfs(root);
65     return 0;
66 }

其实这道题更为详细的解释在这篇博客中也写过了其实:https://www.cnblogs.com/LQS-blog/p/16174901.html

再做一遍加深印象

3.

是这类题的变形

题目给的并不是常规的先序序列和中序序列;

它给的是一组数据的入栈和出站,其实也不难理解,入栈的顺序其实就是先序序列的遍历顺序,而出站的顺序就是中序序列的遍历顺序,这个其实在数据结构课上讲过了,非递归形式的四种遍历方式

无论是我的数据结构恩师还是mooc姥姥的讲解我觉得已经够清楚了,不明白的可以去mooc看一下姥姥对于这节课的讲解哦

回归正题,既然确定了中序和先序序列,那题目就变得和第一题一样了,前提是用栈处理好先序序列和中序序列

其余倒是和第一题没什么太大区别了

参考代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define int long long
 4 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
 5 const int N=100;
 6 int pre[N];
 7 int post[N];
 8 int in[N];
 9 int n;
10 int cnt1=1;
11 int cnt2=1;
12 int k;
13 stack<int>q;
14 struct node
15 {
16     int value;
17     node *l;
18     node *r;
19     node(int value=0,node *l=NULL,node *r=NULL):value(value),l(l),r(r){}
20 };
21 void buildtree(int l,int r,int &t,node *&root)
22 {
23     int flag=-1;
24     for(int i=l;i<=r;i++)
25     {
26         if(in[i]==pre[t])
27         {
28             flag=i;
29             break;
30         }
31     }
32     if(flag==-1)
33     return ;
34     root=new node(in[flag]);
35     t++;
36     if(flag>l)
37     buildtree(l,flag-1,t,root->l);
38     if(flag<r)
39     buildtree(flag+1,r,t,root->r);
40 }
41 void postorder(node *root)
42 {
43     if(root!=NULL)
44     {
45         postorder(root->l);
46         postorder(root->r);
47         post[k++]=root->value;
48     }
49 }
50 signed main()
51 {
52     IOS;
53     char ch[10];
54     int num;
55     cin>>n;
56     for(int i=1;i<=2*n;i++)
57     {
58         cin>>ch;
59         if(strcmp(ch,"Push")==0)
60         {
61             cin>>num;
62             pre[cnt1++]=num;
63             q.push(num);
64         }
65         else
66         {
67             in[cnt2++]=q.top();
68             q.pop();
69         }
70     }
71     int t=1;
72     node *root;
73     buildtree(1,n,t,root);
74     postorder(root);
75     for(int i=0;i<k;i++)
76     {
77         cout<<post[i];
78         if(i<k-1)
79         cout<<" ";
80     }
81   /*  for(int i=1;i<=cnt1;i++)
82     cout<<pre[i]<<" ";
83     cout<<endl;
84      for(int i=1;i<=cnt2;i++)
85     cout<<in[i]<<" ";*/
86     return 0;
87 }

4.二叉树反转

这道题是一道什么样的题呢?

题目是这样讲的:给定二叉树的节点数量

输入n行

从0~n-1进行节点标号

如果存在左或者右孩子就输入数字,没有就输入‘-’

问确定层序序列和中序序列

思路其实可以先不看输入的,因为你看输入不怎么容易确定这颗树是怎样的

可以先看输出

输出给定的当然是层序序列和中序序列

根据层序序列和中序序列确定这颗二叉树的大体模样

3 7 2 6 4 0 5 1
6 5 7 4 3 2 0 1、

 

 根据层序序列在中序序列中不断找到根节点直到把树构造出来就可以了

剩下的问题是确定根节点和反转二叉树

第一、如何确定根节点,我们可以用标记数组标记

输入的时候,如果是数字的话就标记,如果是‘-’return -1,最后遍历一下数组找没被标记的就是根节点了

第二、如何反转二叉树,我们可以后序遍历交换

为什么不用先序序列交换?因为先序序列上来就把左右子树交换,所以访问左子树的时候实际上访问的是右子树,这样是不符合根-左-右的先序遍历方式的,当然,在效果上和后序交换还是一样的,但这样不遵循先序的规则了

其余的遍历方式还是一样的

参考代码:

 1 #include<bits/stdc++.h>//1102
 2 using namespace std;
 3 #define int long long
 4 #define IOS ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0);
 5 const int N=20;
 6 struct node
 7 {
 8     //int key;
 9     int l;
10     int r;
11     node(int l=0,int r=0):l(l),r(r){}
12 }t[N];
13 int n;
14 bool vis[N];//标记数组
15 int cnt1;
16 int cnt2;
17 void bfs(int root)
18 {
19     queue<int>q;
20     q.push(root);
21     while(!q.empty())
22     {
23         int f=q.front();
24         q.pop();
25         cout<<f;
26         cnt1++;
27         if(cnt1<n)
28         cout<<" ";
29         if(t[f].l!=-1)
30         q.push(t[f].l);
31         if(t[f].r!=-1)
32         q.push(t[f].r);
33     }
34     cout<<endl;
35 }
36 void inorder(int root)
37 {
38     if(root!=-1)
39     {
40         inorder(t[root].l);
41         cout<<root;
42         cnt2++;
43         if(cnt2<n)
44         cout<<" ";
45         inorder(t[root].r);
46     }
47 }
48 int findroot()//找到根节点
49 {
50     for(int i=0;i<n;i++)
51     {
52         if(!vis[i])
53         {
54             return i;
55         }
56     }
57 }
58 int findnochild(char c )//找没有孩子的节点,其实是为了找根节点做准备
59 {
60     if(c=='-')
61     return -1;
62     else
63     {
64         vis[c-'0']=true;
65         return (c-'0');
66     }
67 }
68 void swchild(int root)//后序遍历置换
69 {
70     if(root!=-1)
71     {
72         swchild(t[root].l);
73         swchild(t[root].r);
74         swap(t[root].l,t[root].r);
75     }
76 }
77 signed main()
78 {
79     IOS;
80     cin>>n;
81     for(int i=0;i<n;i++)
82     {
83         char lc,rc;
84         cin.get();
85         cin>>lc>>rc;
86         t[i].l=findnochild(lc);
87         t[i].r=findnochild(rc);
88     }
89     int root=0;
90     root=findroot();
91     swchild(root);
92     bfs(root);
93     inorder(root);
94     return 0;
95 }

----------------------------------------------------------------------------2022-8-11 22:24

今天就早休息了,明天在把剩下的几道题更一下//分割线

----------------------------------------------------------------------------

标签:node,binary,后序,int,中序,tree,序列,root,order
来源: https://www.cnblogs.com/LQS-blog/p/16578150.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有