二叉树前序、中序、后序遍历相互求法
参考资料:
[1]:https://blog.csdn.net/m0_37698652/article/details/79218014
一、已知前序、中序遍历,求后序遍历
例:
前序遍历: GDAFEMHZ
中序遍历: ADEFGHMZ
画树求法:
第一步,根据前序遍历的特点,我们知道根结点为G
第二步,观察中序遍历ADEFGHMZ。其中root节点G左侧的ADEF必然是root的左子树,G右侧的HMZ必然是root的右子树。
第三步,观察左子树ADEF,左子树的中的根节点必然是root结点的leftchild。在前序遍历中,root的leftchild紧挨着root之后,所以左子树的根节点为D。
第四步,同样的道理,root的右子树节点HMZ中的根节点也可以通过前序遍历求得。在前序遍历中,一定是先把root和root的所有左子树节点遍历完之后
才会遍历右子树,并且遍历的左子树的第一个节点就是左子树的根节点。同理,遍历的右子树的第一个节点就是右子树的根节点。
第五步,观察发现,上面的过程是递归的。先找到当前树的根节点,然后划分为左子树,右子树,然后进入左子树重复上面的过程,然后进入右子树重复上面的过程。
最后就可以还原一棵树了。
那么,我们可以画出这个二叉树的形状:
那么,根据后序的遍历规则,我们可以知道,后序遍历顺序为:AEFDHZMG
代码如下:
1 /** 2 假设所有节点由互不相等的大写字母组成; 3 将字母'A'~'Z'由'0'~'25'表示 4 */ 5 #include<iostream> 6 #include<cstdio> 7 #include<cstring> 8 using namespace std; 9 #define ls(x) (x<<1) 10 #define rs(x) (x<<1|1) 11 #define mem(a,b) memset(a,b,sizeof(a)) 12 const int maxn=1000; 13 14 int tree[4*maxn]; 15 char preOrder[maxn];//前序遍历 16 char inOrder[maxn];//中序遍历 17 int pos[30];//pos[i]:节点i在中序遍历中的位置 18 19 void DFS(int l,int r,int curPos,int &k) 20 { 21 if(l > r) 22 return ; 23 tree[curPos]=preOrder[k++]-'A'; 24 25 if(l == r) 26 return ; 27 28 /** 29 分别递归左右子树 30 根据前序遍历的特点先递归左子树 31 */ 32 int mid=pos[tree[curPos]]; 33 DFS(l,mid-1,ls(curPos),k); 34 DFS(mid+1,r,rs(curPos),k); 35 } 36 37 void Print(int index) 38 { 39 if(tree[index] == -1) 40 return ; 41 42 Print(ls(index)); 43 Print(rs(index)); 44 printf("%c",'A'+tree[index]); 45 } 46 void Solve() 47 { 48 mem(tree,-1); 49 int len=strlen(preOrder); 50 for(int i=0;i < len;++i) 51 pos[inOrder[i]-'A']=i; 52 53 tree[1]=preOrder[0]-'A';//根节点 54 int k=1; 55 int mid=pos[tree[1]];//求出根节点在中序遍历中的位置 56 DFS(0,mid-1,ls(1),k);//左子树[0,mid-1] 57 DFS(mid+1,len-1,rs(1),k);//右子树[mid+1,len-1] 58 59 Print(1);//输出后序遍历结果 60 } 61 int main() 62 { 63 // freopen("C:/Users/hyacinthLJP/Desktop/stdin/contest","r",stdin); 64 while(~scanf("%s%s",preOrder,inOrder)) 65 Solve(); 66 67 return 0; 68 }
二、已知中序和后序遍历,求前序遍历
依然是上面的题,这次我们只给出中序和后序遍历:
中序遍历: ADEFGHMZ
后序遍历: AEFDHZMG
画树求法:
第一步,根据后序遍历的特点,我们知道后序遍历最后一个结点即为根结点,即根结点为G。
第二步,观察中序遍历ADEFGHMZ。其中root节点G左侧的ADEF必然是root的左子树,G右侧的HMZ必然是root的右子树。
第三步,观察右子树HMZ,右子树的中的根节点必然是root的rightChild。在后序遍历中,root的rightChild紧挨着root之前,所以右子树的根节点为M。
第四部,以此类推,根据后序遍历的特点,紧邻着当前根节点G的前一个节点一定是右子树的根节点,当右子树全部还原后,开始还原左子树;
那么,前序遍历: GDAFEMHZ
代码如下:
1 /** 2 假设所有节点由互不相等的大写字母组成; 3 将字母'A'~'Z'由'0'~'25'表示 4 */ 5 #include<iostream> 6 #include<cstdio> 7 #include<cstring> 8 using namespace std; 9 #define ls(x) (x<<1) 10 #define rs(x) (x<<1|1) 11 #define mem(a,b) memset(a,b,sizeof(a)) 12 const int maxn=100; 13 14 char midOrder[maxn];//中序遍历 15 char nexOrder[maxn];//后序遍历 16 int tree[4*maxn]; 17 int pos[30];//pos[i]:节点i在中序遍历中的位置 18 19 void DFS(int l,int r,int curPos,int &k) 20 { 21 if(l > r) 22 return ; 23 // printf("l=%d,r=%d\n",l,r); 24 tree[curPos]=nexOrder[k--]-'A'; 25 if(l == r) 26 return ; 27 28 /** 29 分别递归右左子树 30 根据前序遍历的特点先递归右子树 31 */ 32 int mid=pos[tree[curPos]]; 33 DFS(mid+1,r,rs(curPos),k); 34 DFS(l,mid-1,ls(curPos),k); 35 } 36 void Print(int index) 37 { 38 if(tree[index] == -1) 39 return ; 40 41 printf("%c",'A'+tree[index]); 42 Print(ls(index)); 43 Print(rs(index)); 44 } 45 void Solve() 46 { 47 mem(tree,-1); 48 int len=strlen(midOrder); 49 for(int i=0;i < len;++i) 50 pos[midOrder[i]-'A']=i; 51 52 tree[1]=nexOrder[len-1]-'A';//根节点 53 int mid=pos[tree[1]];//求出根节点在中序遍历中的位置 54 int k=len-2; 55 DFS(mid+1,len-1,rs(1),k);//右子树[mid+1,len-1] 56 DFS(0,mid-1,ls(1),k);//左子树[0,mid-1] 57 58 Print(1);//前序遍历 59 printf("\n"); 60 } 61 int main() 62 { 63 // freopen("C:/Users/hyacinthLJP/Desktop/stdin/contest","r",stdin); 64 while(~scanf("%s%s",midOrder,nexOrder)) 65 Solve(); 66 67 return 0; 68 }