PAT:树
来源:互联网 发布:怎么测试网络丢包率 编辑:程序博客网 时间:2024/05/21 18:38
1064. 完全二叉搜索树
给定一个数列,要求构造一个完全二叉搜索树,并输出其层序遍历的结果。
思路:
巧妙的思路是利用完全二叉树的的一个特殊属性:
按照层序遍历的顺序给所有节点标号,根节点标1,第二层的左节点标为2,右节点标为3……
记当前节点的下标为i,则其左孩子节点的下标为2i
,右孩子节点的下标为2i+1
。
现在,我们要得到层序遍历的结果,已知的则是排列好的递增序列。
我们注意到,对于一棵完全二叉搜索树,中序遍历可以得到递增序列。反过来,用中序遍历的方法也可以构造出一棵完全二叉搜索树。
在构造的过程中,我们就在tree数组中得到了层序遍历结果。
#include<stdlib.h>#include<iostream>#include<vector>#include<string>#include<queue>#include<stack>#include<limits.h>#include<cmath>#include<set>#include<map>#include<utility>#include<algorithm>using namespace std;vector<int> node;vector<int> tree(1005,0);int pos,n;void build(int root) { if(root>n) return; //计算左子树和右子树的下标位置 int lson = root<<1,rson =(root<<1)+1; build(lson); tree[root] = node[pos++]; build(rson);}int main() { int pp; cin>>n; for(int i=0;i<n;++i) { cin>>pp; node.push_back(pp); } sort(node.begin(),node.end()); pos = 0; build(1); for(int i=1;i<=n;i++) { cout<<tree[i]; if(i!=n) cout<<' '; } cout<<endl; return 0;}
1020. 树的遍历
已知后序遍历和中序遍历的数列,要求构造二叉树,然后按层序输出。
思路:
后序遍历的最后一个元素一定是整棵树的根,从后向前,分别是右、左子树的根。
相应的,中序序列中根结点左边的元素一定属于左子树,右边的元素一定属于右子树。
借鉴BFS层序遍历的思路:
- postorder的最后一个元素即为整棵树的根结点;
- 在inorder中找到该根结点,以它为分界,左边的元素构成左子树,右边的元素构成右子树,将两个范围
[0,i-1] [i+1,n-1]
存入队尾; - 从队首取一个元素(范围),考察inorder中该范围的元素,寻找postorder中从后往前出现的第一个元素,它就是该范围构成的子树的根结点;
- 以该结点为分界,将该范围再细分成两个范围(左、右子树)存入队尾;
- 继续直到队列变空。
#include <iostream>#include <vector>#include <queue>#include <algorithm>using namespace std;struct range { int left; int right;};int n,one;queue<range> que;vector<int> postorder;vector<int> inorder;vector<int> res;//寻找范围函数void search(int left,int right,int root) { if(left>right) return; for(int i=left;i<=right;i++) { if(inorder[i]==root) {//如果找到了这个root range new1={left,i-1}; que.push(new1); range new2={i+1,right}; que.push(new2); break; } }}int main() { //初始化 cin>>n; for(int i=0;i<n;i++) { cin>>one; postorder.push_back(one); } for(int i=0;i<n;i++) { cin>>one; inorder.push_back(one); } range a={0,n-1}; que.push(a); //BFS层序遍历 vector<int>::iterator it,le,ri; while(!que.empty()) {//只要queue非空 //取出队首元素 range aa=que.front(); que.pop(); if(aa.left>aa.right || right<0) continue; //cout<<aa.left<<' '<<aa.right<<endl; //开始在postorder里找指定子树的根节点 le=inorder.begin()+aa.left; ri=inorder.begin()+aa.right+1;//注意这里的范围 //按照范围找出子树的根节点 for(int i=n-1;i>=0;i--) { it=find(le,ri,postorder[i]); if( it != ri ) {//如果找到了该根结点 res.push_back(postorder[i]); search(aa.left,aa.right,postorder[i]); break; } } } for(int i=0;i<n;i++) { cout<<res[i]; if(i < (n-1) ) cout<<' '; } cout<<endl; return 0;}
1021. 求图的最大深度
已知一个图,计算从任何一点开始,以此为根节点,树的最大深度。不保证图的连通性,如果不全部连通,求连通子图的个数。
如果用邻接矩阵的形式保存图形,那么将是O(n*n)的空间复杂度,就是10^8*4B个数据,为4*10^5KB内存,题目是3.2*10^5KB内存,所以内存超出。
所以我们想到的是用邻接表来保存图,但是我们实现的时候不用链表,而是用向量数组vector<int> adj[MAX]
的形式来保存图,这个方式极好,要常用。
#include<stdio.h>#include<string>#include<iostream>#include<vector>using namespace std;#define MAX 10001int maxInt=0xffffffff>>1;bool visited[MAX];int height[MAX];vector<int> adj[MAX];int n;int dfs(int node) { bool flag=false;//node有其他与之相连的结点的标志 int max=-1; visited[node]=true; vector<int>::iterator it=adj[node].begin(); //遍历与node相连的结点 for(;it!=adj[node].end();it++) { int i=*it; if(!visited[i]) { flag=true; int temp=dfs(i); if(max<temp) max=temp; } } if(!flag) return 1; return max+1;}void init() { for(int i=1;i<=n;i++) visited[i]=false;}int main() { while(cin>>n) { int a,b; visited[n]=false; for(int i=1;i<=n;i++) adj[i].clear(); //构建邻接表 for(int i=1;i<=n-1;i++) { visited[i]=false; cin>>a>>b; adj[a].push_back(b); adj[b].push_back(a); } bool iserr=false; int count=1; int max_height=-1; for(int i=1;i<=n;i++) { init(); height[i]=dfs(i); if(height[i]>max_height) max_height=height[i]; //判断是否全部结点都连通 for(int j=1;j<=n;j++) { if(!visited[j]) { count++; dfs(j); } } if(count>1) { iserr=true; break; } } if(iserr) printf("Error: %d components\n",count); else { for(int i=1;i<=n;i++) { if(height[i]==max_height) printf("%d\n",i); } } } return 0;}
1115. 计算BST的最后两行的节点数
给定一组数,要求构造BST,并求该树的最后两行的节点数,并且求和。
思路:
首先根据输入的数列建立二叉搜索树,这里用的是递归的方法。
然后用bfs的方法计算最后最底两层的节点数,最后按照题目要求输出答案。
#include <iostream> #include <vector> #include <queue> using namespace std; struct node { int val; node *left,*right; node(int v):val(v),left(NULL),right(NULL){} }; void build(node *&root,int val) { if(root==NULL) { root=new node(val); return; } if(val<=root->val) build(root->left,val); else build(root->right,val); } int main() { int n; cin>>n; node *root=NULL; for(int i=0;i<n;i++) { int v; cin>>v; build(root,v); } queue<node*>que; que.push(root); int n1=0,n2=0; while(!que.empty()) { n2=n1; n1=que.size(); for(int i=0;i<n1;i++) { node *tmp=que.front(); que.pop(); if(tmp->left) que.push(tmp->left); if(tmp->right) que.push(tmp->right); } } printf("%d + %d = %d\n",n1,n2,n1+n2); }
1119. 前序后序转中序
题意:
给出一棵树的结点个数n,以及它的前序遍历和后序遍历,输出它的中序遍历,如果中序遍历不唯一就输出No,且输出其中一个中序即可,如果中序遍历唯一就输出Yes,并输出它的中序
思路:
用unique标记是否唯一,如果为1就表示中序是唯一的。
已知二叉树的前序和后序是无法唯一确定一颗二叉树的,因为可能会存在多种情况,这种情况就是一个结点可能是根的左孩子也可能是根的右孩子,如果发现了一个无法确定的状态,置unique = 0,又因为题目只需要输出一个方案,可以假定这个不可确定的孩子的状态是右孩子,接下来的问题是如何求根结点和左右孩子划分的问题了。
首先我们需要知道树的表示范围,需要四个变量,分别是前序的开始位置prel,前序的结束位置prer,后序的开始位置postl,后序的结束位置postr,前序的第一个元素和后序的最后一个元素是相等的:树的根结点,以后序的根结点的前面一个结点作为参考,寻找这个结点在前序的位置,就可以根据这个位置来划分左右孩子,递归处理。
#include <cstdio>#include <vector>using namespace std;vector<int> ans;int *pre, *post, unique = 1;int findFromPre (int x, int l, int r) { //在前序中寻找元素x for (int i = l; i <= r; i++) { if (x == pre[i]) { return i; } } return -1;}void setIn (int prel, int prer, int postl, int postr) { //递归地划分左右子树 if (prel == prer) { ans.push_back(pre[prel]); return; } if (pre[prel] == post[postr]) { int x = findFromPre(post[postr - 1], prel + 1, prer); if (x - prel > 1) { setIn(prel + 1, x - 1, postl, postl + x - prel - 2); ans.push_back(post[postr]); setIn(x, prer, postl + x - prel - 2 + 1, postr - 1); } else { unique = 0; ans.push_back(post[postr]); setIn(x, prer, postl + x - prel - 2 + 1, postr - 1); } } }int main() { int n = 0; scanf("%d", &n); pre = new int [n]; post = new int [n]; for (int i = 0; i < n; i++) { scanf("%d", &pre[i]); } for (int i = 0; i < n; i++) { scanf("%d", &post[i]); } setIn(0, n - 1, 0, n - 1); printf("%s\n", unique ? "Yes" : "No"); printf("%d", ans[0]); for (int i = 1; i < ans.size(); i++) { printf(" %d", ans[i]); } printf("\n"); return 0;}
- PAT:树
- pat树
- PAT 1066 平衡树
- pat-笛卡尔树
- PAT判断搜索树
- pat笛卡尔树
- pat 搜索树判断
- 树的遍历---pat
- PAT-二叉搜索树
- PAT甲级 1004 树
- PAT(笛卡尔树)
- pat
- 【PAT】
- PAT
- PAT
- PAT
- PAT
- PAT
- JS正则表达式详解
- 剑指offer之面试题27二叉搜索树与双向链表
- 基于common-fileupload实现文件上传
- 读书笔记(UIKit性能优化解析和Block经典实用)(一)
- Proguard 不要混淆内部类
- PAT:树
- Codeforces Round #352 (Div. 2) ABCD
- svn的branch truck tag
- 遇到的问题总结
- 怎么用Beyond Compare对比图片差异
- Ubuntu16.04 64位系统下面安装JDK1.7
- Qt使用QMediaplayer类做音频播放器
- FFMPEG filter讲解
- Windows环境下Release崩溃定位