二叉树之建树

Posted 大张小张学信奥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二叉树之建树相关的知识,希望对你有一定的参考价值。

概述

今天,我们来谈一谈二叉树建树的方法。(注意,今天不是一道题,而是很多题)

一般来说,建树有两种出题方式:

A.给你一些遍历,让你求出某遍历

B.给你一些表示方法,让你求出某遍历

   


 二叉树储存方法

        二叉树,每个节点都有一个父节点,一个左子节点,一个右子节点(节点可以为空)。所以,二叉树的储存结构就是:   

struct node{ short lchild,rchild,father;} tree[31];

    


出题方法A:

        我们先来了解一下各遍历:

        好了,对于这种题目,我们一般都是找到各个遍历的特征(比如以前讲的前序的第一个是根,中序根左边为左子树等)找规律,然后写出代码。

    (因为题目挺多的,所以我会讲粗糙点)



        例题选讲:

                例题1:

                

二叉树之建树

            这道题,我们先分析遍历:跟前序遍历一样,层次遍历的第一个       也一定是根节点。然后通过中序遍历分出左子树与右子树。不过,子        树层次遍历有点难取,其实只要每次取根节点+1到最后,然后在            下一层递归中一个一个寻找根节点就行了。

    

#include <iostream>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。

#include <iostream>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,那就不做处理了。然后按照中序遍历顺序处理。(比较坑的是,最后一个点有重复的值)

#include <iostream>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 ;

    ·如果遇到的是字母,那么我们进行儿子处理

    ·如果遇到的是逗号,我们进行切换儿子。

    

#include <iostream>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版就行了哦。

以上是关于二叉树之建树的主要内容,如果未能解决你的问题,请参考以下文章

数据结构(12)---二叉树之顺序结构

二叉树之结点相关操作

二叉树之红黑树(RBTree)

二叉树之 二叉树深度

数据结构 二叉树

二叉树之完全二叉树