二叉树之建树
Posted 大张小张学信奥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树之建树相关的知识,希望对你有一定的参考价值。
概述
今天,我们来谈一谈二叉树建树的方法。(注意,今天不是一道题,而是很多题)
一般来说,建树有两种出题方式:
A.给你一些遍历,让你求出某遍历
B.给你一些表示方法,让你求出某遍历
二叉树储存方法
二叉树,每个节点都有一个父节点,一个左子节点,一个右子节点(节点可以为空)。所以,二叉树的储存结构就是:
struct node
{
short lchild,rchild,father;
} tree[31];
出题方法A:
我们先来了解一下各遍历:
好了,对于这种题目,我们一般都是找到各个遍历的特征(比如以前讲的前序的第一个是根,中序根左边为左子树等)找规律,然后写出代码。
(因为题目挺多的,所以我会讲粗糙点)
例题选讲:
例题1:
这道题,我们先分析遍历:跟前序遍历一样,层次遍历的第一个 也一定是根节点。然后通过中序遍历分出左子树与右子树。不过,子 树层次遍历有点难取,其实只要每次取根节点+1到最后,然后在 下一层递归中一个一个寻找根节点就行了。
#
using namespace std;
struct node
{
short lchild,rchild,father;
} tree[31];
int build(char root,string a,string b)
{
if(b=="") return 0;
int pos=0,p;
while ((p=b.find(a[pos],0))==-1 )//寻找根节点
pos++;
string l,r,s;//取左子树与右子树
l=b.substr(0,p);
s=a.substr(pos+1,a.length() -pos-1);
r=b.substr(p+1,b.length() -p-1);
tree[a[pos]-'0'].lchild =build(a[pos],s,l);
tree[a[pos]-'0'].rchild =build(a[pos],s,r);
tree[tree[a[pos]-'0'].rchild].father =a[pos]-'0';
tree[tree[a[pos]-'0'].lchild].father =a[pos]-'0';
return a[pos]-'0';//返回当前子树根节点
}
int ans=0,n;
void front(int root)
{
if (root==0)
return ;
ans++;
cout<<root;
if (ans!=n) //空格处理
cout<<" ";
front(tree[root].lchild );
front(tree[root].rchild );
}
void back(int root)
{
if (root==0)
return ;
back(tree[root].lchild );
back(tree[root].rchild );
ans++;
cout<<root;
if (ans!=n)
cout<<" ";
}
int main(void)
{
int c;
string a,b;
cin>>n;
for (int i=0;i<n;i++)
{
cin>>c;
a+=c+'0';
}
for (int i=0;i<n;i++)
{
cin>>c;
b+=c+'0';
}
int root;
root=build(' ',a,b);
front(root);
ans=0;
cout<<endl;
back(root);
return 0;
}
//这个代码其实有一个bug,就是节点数超过10时理论上会出错
大家可以自己改写数组版。
例题2
(这道题通过率真可怕:100%)
其实,这道题有一个性质,只要你搜到一个“.”,你就知道不用往下 搜了。对于每个点,我们搜两个,一个是左儿子,一个是右儿子。
我们保持一个now,表示现在搜到第几个位置了。每新搜一个点,我 们都对now++,遇到"."时return。
#
using namespace std;
string str;
struct node
{
char father=NULL,lchild=NULL,rchild=NULL;
} tree[60];
int now=0;
void build()
{
if (str[now]=='.')
return ;
int last=now;
if (str[now+1]!='.')
{
tree[str[now]-'A'].lchild =str[now+1];
tree[str[now+1]-'A'].father =str[now];
}
++now;
build();
if (str[now+1]!='.')
{
tree[str[last]-'A'].rchild =str[now+1];
tree[str[now+1]-'A'].father =str[last];
}
++now;
build();
}
void midlle(char root)
{
if (tree[root-'A'].lchild !=NULL)
midlle(tree[root-'A'].lchild );
cout<<root;
if (tree[root-'A'].rchild !=NULL)
midlle(tree[root-'A'].rchild );
}
void back(char root)
{
if (tree[root-'A'].lchild !=NULL)
back(tree[root-'A'].lchild );
if (tree[root-'A'].rchild !=NULL)
back(tree[root-'A'].rchild );
cout<<root;
}
int main(void)
{
cin>>str;
//str+='.';
build ();
midlle(str[0]);
cout<<endl;
back(str[0]);
return 0;
}
出题方法B:
二叉树主要表示法:
1.最朴实的,告诉你某节点的左儿子,右儿子。
2.括号表示法,即儿子用括号括起来。
对于求出这种方法,我们一般都是按部就班,他怎么说就怎么做(表示法1),其他表示法,找到他的表示原理就行了。
例题1:
这道题,我们按部就班,如果儿子的值为0,那就不做处理了。然后按照中序遍历顺序处理。(比较坑的是,最后一个点有重复的值)
using namespace std;
int ans=0;
int a=-1,root,flag=0,x;
struct node
{
int lchild=0,rchild=0,father=-1,data;
int m=0; //m表示左右儿子度.
} tree[101];
void f(int now)
{
if (flag==1)
return ;
if (tree[now].lchild!=0)//有左儿子
{
f(tree[now].lchild );
}
if (flag)
return ;
ans++;
if (tree[now].data==x)
{
cout<<ans<<endl;
flag=1;
return ;
}
if (tree[now].rchild!=0)
f(tree[now].rchild );
}
int main(void)
{
int n;
cin>>n;
int root;
for (int i=1;i<=n;i++)
{
int l,r;
cin>>tree[i].data >>l>>r;
if (l>0)
{
tree[i].m++;
tree[i].lchild =l;
tree[l].father =i;
}
if (r>0)
{
tree[i].m++;
tree[i].rchild =r;
tree[r].father =i;
}
}
cin>>x;
for (int i=1;i<=n;i++)
{
if (x==tree[i].data )
a=i;
if (tree[i].father==-1)
root=i;
}
if (a==-1)
{
cout<<"NO"<<endl;
return 0;
}
f(root);
return 0;
}
例题2:
这道题的字符要一个一个去读,不可以一串读进来。
我们通过一个while来读字符串,
·如果遇到的是),@,我们return ;
·如果遇到的是字母,那么我们进行儿子处理
·如果遇到的是逗号,我们进行切换儿子。
using namespace std;
struct node
{
char father=NULL,child[2]={NULL,NULL};
} tree[30];
char build(char root)
{
char a,nr;
int l=0;
while (cin>>a && (a!='@' && a!=')'))
{
if (a>='A' && a<='Z')
{
if (root!=' ')
{
tree[root-'A'].child [l]=a;
tree[a-'A'].father =root ;
}
nr=a;
}
if (a=='(')
build(nr);
else if (a==',')
l++;
}
return nr;
}
void print(char root)
{
if (tree[root-'A'].child [0]!=NULL)
print(tree[root-'A'].child [0]);
if (tree[root-'A'].child [1]!=NULL)
print(tree[root-'A'].child [1]);
cout<<root;
}
int main(void)
{
print(build (' '));
return 0;
}
好了,今天就讲到这里。
还记得出题方法A里面例题1有BUG让你们自己写Int版吗,其实只要把字符串改成数组,然后将各大字符串函数改成Int版就行了哦。
以上是关于二叉树之建树的主要内容,如果未能解决你的问题,请参考以下文章