• 二叉树的遍历


      算法题目中有很多关于二叉树遍历的题目,以下就简要说一下可能的情况:

        1、已知先序和中序,求后序。比如先序1 2 3 4 6 7 5,中序2 1 6 4 7 3 5。主要步骤有:1、求当前父节点,该节点是当前先序序列的第一个。2、在中序节点中找出该父节点的位置(i,从0开始计数)。3、获得左右孩纸节点,中序的序列左右孩纸(0到i-1),(i,len-1),先序左右孩纸就是(1,i)(i+1,len-1)。整理出:左孩纸先序节点(0,i-1),中序序列节点(1,i),右孩纸的先序(i,len-1),中序是(i+1,len-1)。4分别对左右孩纸进行1步骤。

    #include<iostream>
    #include<cstdio>
    #include<set>
    #include<map>
    #include<vector>
    #include<iterator>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    struct Node
    {
        int key;
        Node* left;
        Node* right;
        Node(){left=right=NULL;}
    };
    void post_travel(Node* root)
    {
        if(root==NULL)
        {
            return;
        }
        post_travel(root->left);
        post_travel(root->right);
        printf("%d ",root->key);
    }
    Node* CreateTree(int* pre,int* inorder,int len)
    {
        if(len<=0) return NULL;
        Node* node = new Node();
        node->key = *pre;
        if(len==1)
        {
            return node;
        }
        int i;
        for(i=0;i<len;++i)
        {
            if(inorder[i]==*pre)
            {
                break;
            }
        }
        node->left= CreateTree(pre+1,inorder,i);
        node->right = CreateTree(pre+i+1,inorder+i+1,len-i-1);
        return node;
    }
    int main()
    {
        freopen("test.txt","r",stdin);
        int n;
        scanf("%d",&n);
        int pre[n],inorder[n];
        for(int i=0;i<n;++i)
        {
            scanf("%d",&pre[i]);
        }
        for(int i=0;i<n;++i)
        {
            scanf("%d",&inorder[i]);
        }
        Node* root = CreateTree(pre,inorder,n);
        post_travel(root);
        return 0;
    }
    View Code

         另一种解法:把树想象成一颗BST,根据中序遍历构造val与中序顺序自己的对应,然后遍历先序插入的时候,判断当前节点阶段编号是在val对应编号的左边还是右边(有没有很像bst的插入)

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<map>
    using namespace std;
    
    struct Node
    {
        int val;
        Node* left;
        Node* right;
        Node(){left = right=NULL;}
    };
    map<int,int> valtoid;
    Node* Insert(Node* node,int val)
    {
        if(node==NULL)
        {
            node = new Node();
            node->val = val;
        }
        else if(valtoid[val]<valtoid[node->val])
            node->left = Insert(node->left,val);
        else
            node->right = Insert(node->right,val);
        return node;
    }
    void post_travel(Node* node)
    {
        if(NULL==node) return;
        post_travel(node->left);
        post_travel(node->right);
        printf("%d ",node->val);
    }
    int main()
    {
        int n;
        scanf("%d",&n); //输入个数
        int pre[n];
        for(int i=0;i<n;++i) scanf("%d",&pre[i]);   //输入先序
        for(int i=0;i<n;++i)    //输入后序
        {
            int a;
            scanf("%d",&a);
            valtoid[a] = i;
        }
        Node* root = NULL;
        for(int i=0;i<n;++i) root = Insert(root,pre[i]);
        post_travel(root);
        puts("");
    }
    /*测试
    7
    6 5 8 7 3 2 4
    8 5 7 6 2 3 4
    输出 8 7 5 2 4 3 6
    */
    View Code

         2、已知先序和后序,求中序(PAT原题1119)

        难点在先序和后序构造的树不一定唯一,当然也有可能唯一解。所以我们要知道什么时候二叉树不唯一,什么时候唯一呢?那例题来说1 2 3 4 6 7 5和2 6 7 4 5 3 1,我们第一步可以得到当前父节点1。然后如何判断左右孩纸呢。

    先序1后面那个就是下一个节点(2),后序1前面那个就是下一个节点(3),这时候你发现2和3不一样,说明什么呢--其实说明一个是左孩纸,一个是有孩纸。然后从先序中找右孩纸(3)的节点位置,然后我们可以找到左右孩纸的两颗树的序:左孩纸树的先序序列2,后序也是2,右孩纸的先序序列就是3 4 6 7 5,后序序列是6 7 4 5 3。然后不断重复以上步骤就好了。

    再看另一个例子:1 2 3 4、2 4 3 1。为什么不唯一呢,找左右孩纸序列,左孩纸2 右孩纸3 4(先序),4 3(后序)。然后对右孩纸进行递归,你会发现根节点是3,孩纸节点只有一个(4),然后你就不知道他是属于左节点还是右节点了,所以不唯一。

    所以结论:先序和后序求中序,要求必须是孩纸节点要么没有,要么是2个,不能有任意节点只有一个孩纸节点。

    #include<iostream>
    #include<cstdio>
    #include<set>
    #include<map>
    #include<vector>
    #include<iterator>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    struct Node
    {
        int key;
        Node* left;
        Node* right;
        Node()
        {
            left = right = NULL;
        }
    };
    bool bOnly = true;
    Node* CreateTree(int* pre,int *post,int len)
    {
        Node *node = new Node();
        node->key = *pre;
        if(len != 1)
        {
            //printf("len=%d
    ",len);
            if(*(pre+1) == *(post+len-2))
            {
                bOnly = false;
                node->left = CreateTree(pre+1,post,len-1);
            }
            else
            {
                int rightkey = *(post+len-2);
                int rightindex = 0;
                for(;rightindex<len;++rightindex)
                {
                    if(rightkey == *(pre+rightindex))
                    {
                        break;
                    }
                }
                node->left = CreateTree(pre+1,post,rightindex-1);
                node->right = CreateTree(pre+rightindex,post+rightindex-1,len-rightindex);
            }
        }
        return node;
    }
    bool bFirst = true;
    void inorder_travel(Node* root)
    {
        if(root == NULL) return;
        inorder_travel(root->left);
        if(bFirst) bFirst = false;
        else printf(" ");
        printf("%d",root->key);
        inorder_travel(root->right);
    }
    int main()
    {
        //freopen("test.txt","r",stdin);
        int n;
        scanf("%d",&n);
        int pre[n],post[n];
        for(int i=0;i<n;++i)
            scanf("%d",&pre[i]);
        for(int i=0;i<n;++i)
            scanf("%d",&post[i]);
        Node* root = CreateTree(pre,post,n);
        if(bOnly)
        {
            printf("Yes
    ");
        }
        else
        {
            printf("No
    ");
        }
        inorder_travel(root);
        printf("
    ");
        return 0;
    }
    View Code

            3、完全二叉树,已知中序排序求广度排序(PAT1064原题)

      1064题是用二叉搜索树,所以先需要排序一下,然后构造树就行了

    #include<iostream>
    #include<cstdio>
    #include<set>
    #include<map>
    #include<vector>
    #include<iterator>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    struct Node
    {
        int key;
        Node* left;
        Node* right;
        Node(){left=right=NULL;}
    };
    int n;
    int index2 = 0;
    Node* CreateTree(int* a,int k)
    {
        if(k>=n) return NULL;
        Node* node = new Node();
        node->left = CreateTree(a,2*k+1);
        node->key = a[index2++];
        node->right = CreateTree(a,2*k+2);
        return node;
    }
    bool bFirst = true;
    void level_travel(vector<Node*> vn)
    {
        if(vn.size()==0) return;
        vector<Node*> vnnext;
        for(int i=0;i<vn.size();++i)
        {
            if(bFirst) bFirst = false;
            else printf(" ");
            printf("%d",vn[i]->key);
            if(vn[i]->left) vnnext.push_back(vn[i]->left);
            if(vn[i]->right) vnnext.push_back(vn[i]->right);
        }
        level_travel(vnnext);
    }
    int main()
    {
        //freopen("test.txt","r",stdin);
        scanf("%d",&n);
        int inorder[n];
        for(int i=0;i<n;++i)
            scanf("%d",&inorder[i]);
        sort(inorder,inorder+n);
        Node* root = CreateTree(inorder,0);
        vector<Node*> vn;
        vn.push_back(root);
        level_travel(vn);
        return 0;
    }
    View Code

           另一种求法:

    int index2 = 0;
    void createtree(int* a,int* inorder,int k,int n)
    {
        if(k>=n) return;
        createtree(a,inorder,2*k+1,n);
        a[k] = inorder[index2++];
        createtree(a,inorder,2*k+2,n);
    }
    //广度求中序
    void createtree2(int* a,int* inorder,int k,int n)
    {
        if(k>=n) return;
        createtree2(a,inorder,2*k+1,n);
        inorder[index2++] = a[k];
        createtree2(a,inorder,2*k+2,n);
    }
    View Code

       4、搜索二叉树,已知先序排序求后序排序(PAT1135题)

      由于是搜索二叉树,可以知道左节点肯定比父节点小,右节点肯定比父节点大,先序排序其实就是插入的顺序,根据插入的顺序求树。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    struct Node
    {
        int val;
        Node* left;
        Node* right;
        Node(){left=right=NULL;}
    };
    Node* Insert(Node* node,int val)
    {
        if(node==NULL)
        {
            node = new Node();
            node->val = val;
            return node;
        }
        if(val < node->val)
            node->left = Insert(node->left,val);
        else if(val > node->val)
            node->right = Insert(node->right,val);
        return node;
    }
    void post_travel(Node* node)
    {
        if(node==NULL) return;
        post_travel(node->left);
        post_travel(node->right);
        printf("%d ",node->val);
    }
    int main()
    {
        int n;
        Node* root = NULL;
        scanf("%d",&n);
        for(int i=0;i<n;++i)
        {
            int a;
            scanf("%d",&a);
            root = Insert(root,a);
        }
        post_travel(root);
        printf("
    ");
        return 0;
    }
    /*测试数据1
    7
    4 2 1 3 6 5 7
    输出:1 3 2 5 7 6 4
    */
    /*测试数据2
    7
    3 2 1 6 4 5 7
    输出:1 2 5 4 7 6 3
    */
    View Code

         

           5、关于后序和中序构造数与先序和中序构树的关系,并且如何用一个算法就能通用的构树。https://www.cnblogs.com/jlyg/p/10402919.html

  • 相关阅读:
    YL杯超级篮球赛 (Standard IO)
    Window (Standard IO)
    toj1026 Network 双连通分量
    poj3177 Redundant Paths 双连通分量
    poj1144 Network 双连通分量
    bzoj1269
    bzoj1800
    CF911D
    CF910C
    CF910B
  • 原文地址:https://www.cnblogs.com/jlyg/p/10354622.html
Copyright © 2020-2023  润新知