【二叉树】 给出二叉树的中序遍历 和先序遍历或后序遍历 确定二叉树.md

说明 - 2022-05-05

本篇博客为本人原创, 原发布于CSDN, 在搭建个人博客后使用爬虫批量爬取并挂到个人博客, 出于一些技术原因博客未能完全还原到初始版本(而且我懒得修改), 在观看体验上会有一些瑕疵 ,若有需求会发布重制版总结性新博客。发布时间统一定为1111年11月11日。钦此。

讨论的内容如题

分析

拿中序遍历和后序遍历的组合举例子
设数组last[]储存后续遍历 in[]中序遍历,它们的长度都是n(数组从1开始计,下标范围是1-n)

树根自然为last[n]
,这时我们遍历in[]数组,在in[]数组中找到last[n]的值的下标idx,因为in[]储存的是中序遍历,显然我们以idx为界把in数组的序列分成两份[1,idx-1],[idx+1,n],分别为两颗子树上的节点。

之后我们便可以在分出的两个区间之中重复上述操作,分别找目前子树的根节点,再二分区间,直到获得完整的二叉树

可以使用递归来完成 函数(区间左,区间右,根节点,偏移量)

此时注意一个问题:当区间被二分之后,我们发现后面的区间在in[]数组和last[]数组中的下标“对不齐”了,即下标发生了偏移,如下图。所以要引入一个变量shift来记录偏移量。(偏移量最开始是0,递归时前面的区间继承原偏移量,后面的区间偏移量为原偏移量+1)
![在这里插入图片描述](https://img-blog.csdnimg.cn/20201008231828150.png?x-oss-
process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dsZGNtenk=,size_16,color_FFFFFF,t_70#pic_center)
(在前序遍历和中序遍历的组合中,下标发生偏移的是前面的区间)

例题 后序遍历和中序遍历的组合

https://vjudge.net/contest/386054#problem/E


#include
#include
#include
struct Node
{
int l,r;
};
Node treeN[10010];
int inorder[10010],postorder[10010];
int len,rt,least,lstPos;
int input()//返回数组长度
{
int n,idx=1;
char ch;
while(scanf("%d",&n)!=EOF)
{
inorder[idx++]=n;
ch=getchar();
if(ch==’\n’)
break;
}
idx=1;
while(scanf("%d",&n)!=EOF)
{
postorder[idx++]=n;
ch=getchar();
if(ch==’\n’)
break;
}
return idx-1;
}
int makeTree(int l,int r,int root,int n)
{
if(l>r)
return -1;
int idx=-1;
for(int i=l; i<=r; i++)
{
if(inorder[i]root)
{
idx=i;
break;
}
}
if(idx>0)
{
treeN[root].l=makeTree(l,idx-1,postorder[idx-n-1],n);
treeN[root].r=makeTree(idx+1,r,postorder[r-n-1],n+1);
}
return root;
}
void add(int root,int base)
{
int total=base+root;
if(treeN[root].l
-1 && treeN[root].r==-1)
{
if(lstPos==-1)
{
least=total;
lstPos=root;
}
else
{
if(total<least)
{
least=total;
lstPos=root;
}
}
return ;
}
if(treeN[root].l>0)
{
add(treeN[root].l,total);
}
if(treeN[root].r>0)
{
add(treeN[root].r,total);
}
}

int main()
{
    while((len=input())>0)
    {
        memset(treeN,-1,sizeof(treeN));
        lstPos=-1;
        rt=makeTree(1,len,postorder[len],0);
        add(rt,0);
        std::cout << lstPos << std::endl;
    }
    return 0;
}

例题 前序遍历和中序遍历的组合

<https://pintia.cn/problem-
sets/1303281293857476608/problems/1303281404742291466>


#include
#include
#include
#include
#include
#include
#include
#include

const int N=32;
int n;
struct Node
{
    int l,r;
}treeN[N];
int pre[N],in[N];

int fff(int root,int l,int r,int shift)
{
    if(l>r) return -1;
    int i;
    for(i=l; i<=r; i++) if(root==in[i]) break;
    if(i<=r)
    {
        treeN[root].l=fff(pre[l+1+shift],l,i-1,shift+1);
        treeN[root].r=fff(pre[i+1+shift],i+1,r,shift);
    }
    return root;
}

void rev(int root)
{
    if(root==0) return ;
    treeN[root].r=treeN[root].r^treeN[root].l;
    treeN[root].l=treeN[root].r^treeN[root].l;
    treeN[root].r=treeN[root].r^treeN[root].l;
    rev(treeN[root].l);
    rev(treeN[root].r);
}

void gogogo(int root)
{
    std::queue<int >q;
    std::cout << root;
    if(treeN[root].l!=-1) q.push(treeN[root].l);
    if(treeN[root].r!=-1) q.push(treeN[root].r);
    while(!q.empty())
    {
        root=q.front(); q.pop();
        std::cout << " " << root;
        if(treeN[root].l!=-1) q.push(treeN[root].l);
        if(treeN[root].r!=-1) q.push(treeN[root].r);
    }
}

int main()
{
    std::cin >> n;
    for(int i=0; i<n; i++) std::cin >> in[i];
    for(int i=0; i<n; i++) std::cin >> pre[i];
    int root=fff(pre[0],0,n-1,0);
    rev(root);
    gogogo(root);
    return 0;
}