zoukankan      html  css  js  c++  java
  • 二叉树遍历题型汇总

    第一类问题:根据前(后)序、中序生成树

    模板(以根据后序、中序为例):

    Node* build_tree(int ps,int pe,int is,int ie){
        if(ps>pe) return NULL;
        if(ps==pe) return new Node(in[is]);
        int i=is;
        while(i<=ie && in[i]!=post[pe]) i++;
        Node * node=new Node(in[i]);
        int dLeft=i-is;    //左侧元素数量 
        node->l=build_tree(ps,ps+dLeft-1,is,is+dLeft-1);
        node->r=build_tree(ps+dLeft,pe-1,i+1,ie);
        return node;
    }

    OJ实例:Tree Traversals

    AC代码:

    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    #include <string>
    #include <vector>
    #include <set>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <map>
    
    #define I scanf
    #define OL puts
    #define O printf
    #define F(a,b,c) for(a=b;a<c;a++)
    #define FF(a,b) for(a=0;a<b;a++)
    #define FG(a,b) for(a=b-1;a>=0;a--)
    #define LEN 1010
    #define MAX (1<<30)-1
    #define V vector<int>
    
    using namespace std;
    
    int post[LEN];
    int in[LEN];
    
    typedef struct Node{
        int d;
        struct Node* l=NULL;
        struct Node* r=NULL;
        Node(int d):d(d){
        }
    };
    
    Node* build_tree(int ps,int pe,int is,int ie){
        if(ps>pe) return NULL;
        if(ps==pe) return new Node(in[is]);
        int i=is;
        while(i<=ie && in[i]!=post[pe]) i++;
        Node * node=new Node(in[i]);
        int dLeft=i-is;    //左侧元素数量 
        node->l=build_tree(ps,ps+dLeft-1,is,is+dLeft-1);
        node->r=build_tree(ps+dLeft,pe-1,i+1,ie);
        return node;
    }
    
    int main(){
    //    freopen("1020.txt","r",stdin);
        int i,n;
        I("%d",&n);
        FF(i,n) I("%d",&post[i]);
        FF(i,n) I("%d",&in[i]);
        Node* root=build_tree(0,n-1,0,n-1);
        queue<Node*> q;
        q.push(root);
        int cnt=0;
        while(!q.empty()){
            int sz=q.size();
            Node* t=q.front();
            q.pop();
            cnt++;
            O("%d",t->d);
            if(cnt!=n)O(" ");
            if(t->l)
                q.push(t->l);
            if(t->r)
                q.push(t->r);            
        }
        return 0;
    }
    View Code

    第二类问题:根据前(后)序、中序生成后(前)序 序列

    模板

    根据前序、中序生成后序:

    //caution: should using initialize code: " t=0; "
    //pre in -> post
    //        pre_start pre_end in_start in_end
    void setPost(int ps,int pe,int is,int ie){
        if(ps>pe)return;//null
        if(ps==pe){
            post[t++]=pre[ps];
        }else{
            //find the elem is the pair of preOrder (ps)
            int i=is;
            while(in[i]!=pre[ps] && i<ie) i++;//redirect
            //left
            setPost(ps+1, ps+i-is, is, i-1);
            //right
            setPost(ps+i-is+1, pe, i+1, ie);
            //root
            post[t++]=pre[ps];
        }
    }

    根据后序、中序生成前序:

    //caution: should using initialize code: " t=0; "
    //post in -> pre
    //        post_start post_end in_start in_end
    void setPre(int ps,int pe,int is,int ie){
        if(ps>pe)return;//null
        if(ps==pe){
            pre[t++]=post[ps];
        }else{
            //find the elem is the pair of preOrder (ps)
            int i=is;
            while(in[i]!=post[pe] && i<ie) i++;//redirect
            //root
            pre[t++]=post[pe];
            //left
            setPre(ps, ps+i-is-1, is, i-1);
            //right
            setPre(ps+i-is, pe-1, i+1, ie);
        }
    }

    OJ实例:Postorder Traversal

    AC代码:

    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    #include <string>
    #include <vector>
    #include <set>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <map>
    
    #define I scanf
    #define OL puts
    #define O printf
    #define F(a,b,c) for(a=b;a<c;a++)
    #define FF(a,b) for(a=0;a<b;a++)
    #define FG(a,b) for(a=b-1;a>=0;a--)
    #define LEN 50001
    #define MAX (1<<30)-1
    #define V vector<int>
    
    using namespace std;
    
    int t=0;
    int pre[LEN];
    int post[LEN];
    int in[LEN];
    
    void setPost(int ps,int pe,int is,int ie){
        if(ps>pe) return;
        if(ps==pe){
            post[t++]=pre[ps];
            return;
        }
        int i=is;
        while(i<=ie && pre[ps]!=in[i]) i++;
        int ln=i-is;    //left_num
        setPost(ps+1,ps+ln,is,i-1);
        setPost(ps+ln+1,pe,i+1,ie);
        post[t++]=pre[ps];
    }
    
    int main(){
    //    freopen("1138.txt","r",stdin);
        int i,n;
        I("%d",&n);
        FF(i,n) I("%d",&pre[i]);
        FF(i,n) I("%d",&in[i]);
        setPost(0,n-1,0,n-1) ;
        printf("%d",post[0]) ;
        return 0;
    }
    View Code

    第三类问题:根据前序、后序生成中序(多种可能)

    我以前写的分析博客:二叉树 | 根据前序、后序生成中序

    模板

    (以pat甲级1119为例,如果多个可能只输出其中一种。如果要执行其他的操作请读者修改)

    void setIn(int preS,int preE,int postS,int postE){
        if(preS>preE) return;
        if(preS==preE){
            in[t++]=pre[preS];
            return;
        }
        int i=postS;
        while(i<=postE-1 && post[i]!=pre[preS+1]) i++;
        int ln=i-postS+1;    //left_num
        if(i==postE-1){        //more than one condition
            yes=0;
            //默认找到的结点都为【左结点】。(如果想设置为“右结点”,可以改变setIn递归函数的位置) 
            setIn(preS+1,preS+ln,postS,postS+ln-1);
            in[t++]=pre[preS];
            return;
        }
        setIn(preS+1,preS+ln,postS,postS+ln-1);
        in[t++]=pre[preS];
        setIn(preS+ln+1,preE,postS+ln,postE-1);
    }

    实际应用:

    问题一:已知前序和后序,问是否有唯一的中序,并且输出其中一种中序遍历序列。

    OJ链接:Pre- and Post-order Traversals

    AC代码:

    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    #include <string>
    #include <string.h>
    #include <vector>
    #include <set>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <map>
    
    
    #define I scanf
    #define OL puts
    #define O printf
    #define F(a,b,c) for(a=b;a<c;a++)
    #define FF(a,b) for(a=0;a<b;a++)
    #define FG(a,b) for(a=b-1;a>=0;a--)
    #define LEN 3000
    #define MAX 0x06FFFFFF
    #define V vector<int>
    
    using namespace std;
    
    int t;
    int post[LEN];
    int in[LEN];
    int pre[LEN];
    bool yes=1;
    
    void setIn(int preS,int preE,int postS,int postE){
        if(preS>preE) return;
        if(preS==preE){
            in[t++]=pre[preS];
            return;
        }
        int i=postS;
        while(i<=postE-1 && post[i]!=pre[preS+1]) i++;
        int ln=i-postS+1;    //left_num
        if(i==postE-1){        //more than one condition
            yes=0;
            //默认找到的结点都为【左结点】。(如果想设置为“右结点”,可以改变setIn递归函数的位置) 
            setIn(preS+1,preS+ln,postS,postS+ln-1);
            in[t++]=pre[preS];
            return;
        }
        setIn(preS+1,preS+ln,postS,postS+ln-1);
        in[t++]=pre[preS];
        setIn(preS+ln+1,preE,postS+ln,postE-1);
    }
    
    int main(){
    //    freopen("1119_2.txt","r",stdin);
        int n,i;
        I("%d",&n);
        FF(i,n) I("%d",&pre[i]);
        FF(i,n) I("%d",&post[i]);
        setIn(0,n-1,0,n-1);
        puts(yes?"Yes":"No");
        FF(i,n){
            O("%d",in[i]);
            if(i!=n-1) O(" ");
        }
        puts("");
        return 0;
    }
    View Code

    问题二:已知前序和后序,问有多少种形态的二叉树。

    思路:在上文模板的基础上,在检测到有一组结点既可以当左子树,又可以当右子树时,cnt++(记录这样的结点出现的个数)。最后输出cnt的二次幂(假如有一个这样的结点,那就有左右两种形态。如果有两个,在控制左右形态的同时,左右又各有左右两种形态,一次类推,比图cnt=3 ,ans就等于8 ……)

    OJ链接:1022: 二叉树

    AC代码:

    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    #include <string>
    #include <string.h>
    #include <vector>
    #include <set>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <map>
    
    
    #define I scanf
    #define OL puts
    #define O printf
    #define F(a,b,c) for(a=b;a<c;a++)
    #define FF(a,b) for(a=0;a<b;a++)
    #define FG(a,b) for(a=b-1;a>=0;a--)
    #define LEN 3000
    #define MAX 0x06FFFFFF
    #define V vector<int>
    
    using namespace std;
    
    int t;
    char post[LEN];
    char pre[LEN];
    int cnt;
    
    void calc(int preS,int preE,int postS,int postE){
        if(preS>=preE) return;
        int i=postS;
        while(i<=postE-1 && post[i]!=pre[preS+1]) i++;
        int ln=i-postS+1;    //left_num
        if(i==postE-1) cnt++;
        calc(preS+1,preS+ln,postS,postS+ln-1);
        calc(preS+ln+1,preE,postS+ln,postE-1);
    }
    
    int pow(int n){
        int ans=1;
        while(n--){
            ans*=2;
        }
        return ans;
    }
    
    int main(){
    //    freopen("1022:二叉树.txt","r",stdin);
        while(~scanf("%s%s",pre,post)){
            int n;
            n=strlen(pre);
            cnt=0;
            calc(0,n-1,0,n-1);
            O("%d
    ",pow(cnt));        
        }
    
        return 0;
    }
    View Code

    当然还可以延伸出很多问题,比如要求输出所有这样形态的二叉树的层序或者中序。只要搞清楚问题的本质,题目再怎么变形都不在话下。

    第四类问题:根据中序和层序来建树

    参考博客:[二叉树建树] 复原二叉树(层序和中序)

    思路:

    在main主程序段,在外循环用循环变量i对layer数组从左到右进行遍历,然后在内循环用循环变量j对in数组进行遍历。

    匹配到in[j]==layer[i]时,退出循环,调用建树函数(在主程序段,一共调用n次)

    在建树函数:

      如果传入的root结点是空指针,就把找到的结点赋值给这个空结点。

      如果非空,通过一个映射判断传入结点在in数组的索引是否比root在in数组的索引小。

        如果小,说明是root的左子树,递归调用建树函数。

        如果大,说明是root的右子树,递归调用建树函数。

    模板

    数据结构:

    typedef struct Node{
        int d;
        struct Node* l; 
        struct Node* r; 
        Node(int d):d(d){
            l=r=NULL;
        }
    }; 
    Node * root;
    map<int,int> num2index; //求一个数在中序中的索引 
    int layer[LEN];
    int in[LEN];

    核心代码:

    //主程序段调用
    for(int i=1;i<=n;i++){    //循环变量 i 遍历整个 layer 数组
        j=1;
        while(j<=n && in[j]!=layer[i]) j++;    //找到in[j]==layer[i]
        num2index[in[j]]=j; //这个数在中序中的索引
        build_tree(root,j);
    }
    //建树函数
    void build_tree(Node* & root,int i){// index
        if(!root){
            root=new Node(in[i]);
            return;
        }
        int ri=num2index[root->d];    //root_index;
        if(i<ri) build_tree(root->l,i);
        else     build_tree(root->r,i);
    }

    下面我们通过一个OJ例题来演示一下。

    OJ链接:1010: 还原二叉树

    AC代码:

    #include <stdio.h>
    #include <memory.h>
    #include <math.h>
    #include <string>
    #include <string.h>
    #include <vector>
    #include <set>
    #include <stack>
    #include <queue>
    #include <algorithm>
    #include <map>
    
    
    #define I scanf
    #define OL puts
    #define O printf
    #define F(a,b,c) for(a=b;a<c;a++)
    #define FF(a,b) for(a=0;a<b;a++)
    #define FG(a,b) for(a=b-1;a>=0;a--)
    #define LEN 3000
    #define MAX 0x06FFFFFF
    #define V vector<int>
    
    using namespace std;
    
    map<int,int> num2index; //求一个数在中序中的索引 
    int layer[LEN];
    int in[LEN];
    int n;
    
    typedef struct Node{
        int d;
        struct Node* l; 
        struct Node* r; 
        Node(int d):d(d){
            l=r=NULL;
        }
    }; 
    Node * root;
    void build_tree(Node* & root,int i){// index
        if(!root){
            root=new Node(in[i]);
            return;
        }
        int ri=num2index[root->d];    //root_index;
        if(i<ri) build_tree(root->l,i);
        else     build_tree(root->r,i);
    }
    
    vector<int> ans;
    
    void preOrder(Node* node){
        if(node){
            ans.push_back(node->d);
            preOrder(node->l);
            preOrder(node->r);
        }
    }
    
    void postOrder(Node* node){
        if(node){
            postOrder(node->l);
            postOrder(node->r);
            ans.push_back(node->d);
        }
    }
    
    void printAns() {
        int sz=ans.size(),i;
        FF(i,sz){
            O("%d",ans[i]);
            if(i!=sz-1) O(" ");
        }
        puts("");
    }
    
    int main(){
    //    freopen("还原二叉树.txt","r",stdin);
        I("%d",&n);
        int i,j;
        F(i,1,n+1) I("%d",&layer[i]);
        F(i,1,n+1) I("%d",&in[i]);
        for(int i=1;i<=n;i++){    //循环变量 i 遍历整个 layer 数组
            j=1;
            while(j<=n && in[j]!=layer[i]) j++;    //找到in[j]==layer[i]
            num2index[in[j]]=j; //这个数在中序中的索引
            build_tree(root,j);
        }
        preOrder(root);
        printAns();
        ans.clear();
        postOrder(root);
        printAns();
        return 0;
    }
    View Code
  • 相关阅读:
    warmup_csaw_2016
    pwn-简单栈溢出
    吃土
    编程中的进制转换
    linux系统安全及应用——账号安全(基本安全措施)
    vmware vSphere虚拟网络之标准交换机(二)
    vmware vSphere虚拟网络(一)
    服务器虚拟化技术概述
    用shell脚本安装apache
    The server of Apache (二)——apache服务客户端验证
  • 原文地址:https://www.cnblogs.com/TQCAI/p/8546737.html
Copyright © 2011-2022 走看看