二叉树先序后序中序的重建与遍历:
先找到根节点,再区分左右子数,然后递归求解
如下图通过根分出左右子树,然后递归求解即可
ZOJ1944 已知前序和中序求后序
#include<cstdio> #include<cstring> #include<iostream> using namespace std; char pre[30],in[30]; int idpre,idin,len; struct node { char ch; node *left,*right; }; node *build(node *root,int l,int r) { if(l>r)return NULL; root=new node(); root->ch=pre[idpre++]; for(int i=l;i<=r;i++) { if(in[i]==root->ch) { root->left=build(root,l,i-1); root->right=build(root,i+1,r); break; } } return root; } void postOrder(node *root) { if(root!=NULL){ postOrder(root->left); postOrder(root->right); printf("%c",root->ch); } } int main() { while(~scanf("%s%s",pre,in)) { node *root; idpre=0; len=strlen(pre); root=build(root,0,len-1); postOrder(root); puts(""); } return 0; }
tip:对于有返回值的函数,要习惯先写return xxx; 否则错在哪都不知道
Pat1086先序建树,后序输出,pop()即父节点对应子数为空
奇怪的是题目的输入只有2*n个操作,虽然符合栈的规则,但是有的节点的子节点是空没有对应pop操作,所以当输入节点数大于2*n的时候,就直接返回空节点啦。
#include<cstdio> #include<cstring> #include<iostream> using namespace std; struct node{ int val; node *left,*right; }; int num,n; node *build(node *root) { num++; if(num>2*n)return NULL; char s[10]; scanf("%s",s); if(s[1]=='u') { int val; scanf("%d",&val); root=new node(); root->val=val; root->left=build(root->left); root->right=build(root->right); } else{ root=NULL; } return root; } void postOrder(node *root) { if(root!=NULL) { postOrder(root->left); postOrder(root->right); num++; if(num==n)printf("%d\n",root->val); else printf("%d ",root->val); } } int main() { while(~scanf("%d",&n)) { node *root; num=0; root=build(root); num=0; postOrder(root); } return 0; }
Pat1020 已知后序和先序求层序
#include<cstdio> #include<cstring> #include<queue> #include<vector> #include<iostream> using namespace std; struct node { int val; node *left,*right; }; int post[50],in[50],n; int idpost; node *build(node *root,int l,int r) { if(l>r)return NULL; root=new node(); root->val=post[idpost--]; for(int i=l;i<=r;i++) { if(in[i]==root->val) { root->right=build(root,i+1,r); root->left=build(root,l,i-1); break; } } return root; } void pre(node *root) { if(root!=NULL) { printf("%d\n",root->val); pre(root->left); pre(root->right); } } void levelOrder(node *root) { queue<node*>q; vector<int>v; q.push(root); while(!q.empty()) { root=q.front(); q.pop(); v.push_back(root->val); if(root->left!=NULL)q.push(root->left); if(root->right!=NULL)q.push(root->right); } for(int i=0;i<v.size();i++){ if(i==v.size()-1)printf("%d\n",v[i]); else printf("%d ",v[i]); } } int main() { while(~scanf("%d",&n)) { for(int i=0;i<n;i++)scanf("%d",&post[i]); for(int i=0;i<n;i++)scanf("%d",&in[i]); idpost=n-1; node *root; root=build(root,0,n-1); levelOrder(root); } return 0; }
二叉搜索(查找)树 BST
二叉搜索树的特点:
1.左子树根节点的值比根小,右子树根节点的值比根大(推论:左子树的最大值一定比右子树的最小值小)
2.左右子树也是二叉搜索树
3.树的最小值一定在最左边,树的最大值一定在最右边
Pat1043 给一个先序遍历的序列,问能否构建二叉搜索树或者二叉搜索树的镜像,如果能,输出后序遍历序列。
通过先序遍历的序列确定根节点,通过二叉搜索树的根节点的值一定小于等于右子树所有节点的值来确定左右子树,然后递归求解。
#include<cstdio> #include<iostream> using namespace std; int a[1010],n; int num; int op; int flag; struct node { int val; node *left,*right; }; node *build(node *root,int l,int r) { if(l>r)return NULL; root=new node(); root->val=a[l]; num++; int flag=1; for(int i=l+1;i<=r;i++) { if(op==0&&a[i]>=a[l]) { int j=i; while(j<n&&a[j]>=a[l])j++; if(j<=r)return NULL; root->left=build(root->left,l+1,i-1); root->right=build(root->right,i,r); flag=0; break; } if(op==1&&a[i]<a[l]) { int j=i; while(j<n&&a[j]<a[l])j++; if(j<=r)return NULL; root->left=build(root->left,l+1,i-1); root->right=build(root->right,i,r); flag=0; break; } } //如果右子树没有节点 左子树要有 if(flag) { root->left=build(root->left,l+1,r); root->right=NULL; } return root; } void postOrder(node *root) { if(root!=NULL) { postOrder(root->left); postOrder(root->right); if(flag){ printf("%d",root->val); flag=0; } else printf(" %d",root->val); } } int main() { while(~scanf("%d",&n)) { for(int i=0;i<n;i++)scanf("%d",&a[i]); node *root; num=0;op=0; root=build(root,0,n-1); flag=1; if(num==n){ puts("YES"); postOrder(root); puts(""); continue; } num=0;op=1; root=build(root,0,n-1); if(num==n){ puts("YES"); postOrder(root); puts(""); continue; } puts("NO"); } return 0; }
pat1099 按给定结构构造BST,层序输出
通过数左子树的节点个数和右子树的结点个数找到根节点,递归求解。
题目要求左子树小于根节点的值,右子树大于等于根节点的值
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<queue> #include<algorithm> using namespace std; #define ll long long int mp[110][2]; int n; int a[110],b[110]; int num(int root) { if(root==-1)return 0; return num(mp[root][0])+num(mp[root][1])+1; } void build(int root,int l,int r) { // printf("root:%d\n",root); if(l>r)return; int mid=num(mp[root][0]); // printf(" mid=%d %d %d\n",mid,l,r); b[root]=a[l+mid]; build(mp[root][0],l,l+mid-1); build(mp[root][1],l+mid+1,r); } void bfs() { vector<int>ans; queue<int>q; q.push(0); while(!q.empty()) { int k=q.front();q.pop(); ans.push_back(k); for(int i=0;i<2;i++) { if(mp[k][i]!=-1) { q.push(mp[k][i]); } } } for(int i=0;i<ans.size();i++) { if(i==ans.size()-1)printf("%d\n",b[ans[i]]); else printf("%d ",b[ans[i]]); } } int main() { while(~scanf("%d",&n)) { for(int i=0;i<n;i++) { scanf("%d%d",&mp[i][0],&mp[i][1]); } for(int i=0;i<n;i++)scanf("%d",&a[i]); sort(a,a+n); build(0,0,n-1); bfs(); } return 0; }