算法题目中有很多关于二叉树遍历的题目,以下就简要说一下可能的情况:
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; }
另一种解法:把树想象成一颗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 */
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; }
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; }
另一种求法:
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); }
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 */
5、关于后序和中序构造数与先序和中序构树的关系,并且如何用一个算法就能通用的构树。https://www.cnblogs.com/jlyg/p/10402919.html