• 二叉树遍历题型汇总


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

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

    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
  • 相关阅读:
    Azure HPC Pack Cluster添加辅助节点
    Azure HPC Pack 辅助节点模板配置
    Azure HPC Pack配置管理系列(PART6)
    Windows HPC Pack 2012 R2配置
    Azure HPC Pack 节点提升成域控制器
    Azure HPC Pack VM 节点创建和配置
    Azure HPC Pack 部署必要条件准备
    Azure HPC Pack 基础拓扑概述
    Azure VM 性能计数器配置
    Maven私仓配置
  • 原文地址:https://www.cnblogs.com/TQCAI/p/8546737.html
Copyright © 2020-2023  润新知