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