二叉樹已知先序和中序或者后序和中序求構造數(這個算法特別神奇)


    首先我先介紹一下關於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
*/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM