• 二叉树已知先序和中序或者后序和中序求构造数(这个算法特别神奇)


        首先我先介绍一下关于BST树,BST树又称搜索二叉树,即任意节点的左节点肯定比该节点小,右节点比该节点大。所以当中序遍历的时候,你会惊奇的发现遍历的val竟然是从小到大排序的。

       如图就是BST树,先序是5 3 2 1 4 8 7 6 9,中序是1 2 3 4 5 6 7 8 9。知道先序序列后,其实进行对先序sort一下其实就可以得到中序了。所以如果已知是BST树,在知道一个先序或者后序我们便可以构建出唯一的一颗树了。其实我们可以对先序的理解就是每次对树的插入,所以我们可以用以下代码进行某一节点的插入:

    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;
    }

       知道BST的先序序列构树后,如何已知后序如何构树呢,是的还是用以上代码,但是两者不同之处用下面的伪代码进行说明:

    pre[n]是先序,post[n]是后序
    已知先序构树
    Node* root = NULL;
    for(int i=0;i<n;++i)
        root = Insert(root,pre[i]);
    //已知后序构树
    for(int i=n-1;i>=0;--i)
        root = Inert(root,post[i]);

      是不是很神奇,两者只需要反一下就行了。为什么呢?我们从上图的3 5 8节点来讲,先序是5 3 8,这是我们知道5是父节点,由于3节点比5小,所以3是左节点,8则是右节点。由于先序是 根 左 右的结构,如果改成根右左的结构呢,此时序列就变成了5 8 3,父节点还是5,左节点还是3,右节点还是8。所以只要保证根节点肯定在左右节点前面就行了。所以如果你把后序序列反转后,你会发现它就是根右左的结构,此时其实对构树还是无影响的。因为构树的左右节点是由中序控制的。

        接下来我们要做得是如何把这个算法用到普通二叉树中呢。这时候我们需要知道如何把普通二叉树转换成搜索二叉树。

    如何把作图转换成右图呢,此时就要用到map来映射了。刚开始我们知道中序排序 2 1 3 6 4 5 7,右边的中序是1 2 3 4 5 6 7,此时我们可以做一个映射,map[左边] = 右边编号。即map[2] = 1,map[1]=2,map[3] = 3,map[6]=4....当这个映射做完后,我们可以在遍历先序或者后序时,把val从根节点开始插入时,如果map[val]比当前节点的对应编号map[node->val]小,说明在左边,不然就在右边。

    以下就是关于 二叉树已知先序或者后序,与中序构树的代码:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<map>
    #include<vector>
    #include<algorithm>
    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 pre_travel(Node* node)
    {
        if(NULL==node) return;
        printf("%d ",node->val);
        pre_travel(node->left);
        pre_travel(node->right);
    }
    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); //输入个数
        vector<int> vn;     //先序或者后序
        for(int i=0;i<n;++i)
        {
            int val;
            scanf("%d",&val);
            vn.push_back(val);
        }
        //reverse(vn.begin(),vn.end());  //如果是后序,就反转
        for(int i=0;i<n;++i)    //输入中序
        {
            int a;
            scanf("%d",&a);
            valtoid[a] = i;
        }
        Node* root = NULL;
        cout<<"先序:";
        for(int i=0;i<n;++i) root = Insert(root,vn[i]);
        pre_travel(root);
        puts("");
        cout<<"后序:";
        post_travel(root);
        puts("");
    }
    /*
    //后序,中序
    11
    7 6 3 5 20 4 24 21 10 1 9
    7 6 5 3 9 4 20 1 10 24 21
    //先序,中序
    11
    9 5 6 7 3 1 4 20 10 21 24
    7 6 5 3 9 4 20 1 10 24 21
    */
  • 相关阅读:
    css | js 实现扩展卡片小demo
    ESLint如何配置
    (js描述的)数据结构[哈希表1.3](10)
    (js描述的)数据结构[哈希表1.2](9)
    VSCode——自定义VSCode背景图片
    VSCode 初次写vue项目并一键生成.vue模版
    (js描述的)数据结构[哈希表1.1](8)
    (js描述的)数据结构[字典](7)
    Vue 实战项目: 硅谷外卖(1)
    脑残式网络编程入门(六):什么是公网IP和内网IP?NAT转换又是什么鬼?
  • 原文地址:https://www.cnblogs.com/jlyg/p/10402919.html
Copyright © 2020-2023  润新知