入门经典_Chap06_例题[二]:二叉树的指针及数组实现
来源:互联网 发布:javabean连接数据库 编辑:程序博客网 时间:2024/05/17 08:22
前言
这波题的所有知识点如下:
- 二叉树的数组实现
- 二叉树的链表实现
- 链表实现的动态化静态方法(内存池)
- 二叉树的四种遍历
- 由二叉树的两种遍历序列(必含中序序列)
- 二叉搜索树
题解如下
UVA-679 - Dropping Balls
思路
有一棵二叉树,最大深度为D,且所有叶子的深度都相同。所有结点从上到下从左到右编号为1, 2, 3,…, 2 D -1。
在结点1处放一个小球,它会往下落。每个内结点上都有一个开关,初始全部关闭,当每次有小球落到一个开关上时,状态都会改变。当小球到达一个内结点时,如果该结点上的开关关闭,则往左走,否则往右走,直到走到叶子结点。
如果直接建树的话数组应该存不下,复杂度应该也说不过去,
但是如果从给出的编号的奇偶性上下手,思路就显而易见了
当编号I是奇数时,它是往左走的第(I+1)/2个小球;
当I是偶数时,它是往右走的第I/2个小球。
代码
int D, I;int main() { #ifdef _LOCAL IN; #endif // _LOCAL int t; cin >>t; while(t--) { cin >> D >> I; int ans = 1; for(int i = 1; i < D; ++i) { if(I&1) I = I/2+1, ans *= 2; else I /= 2, ans = ans*2+1; } cout << ans <<endl; } scanf("-1"); return 0;}
UVA-122 - Trees on the level
思路
输入一棵二叉树,你的任务是按从上到下、从左到右的顺序输出各个结点的值。每个结点都按照从根结点到它的移动序列给出(L表示左,R表示右)。
在输入中,每个结点的左括号和右括号之间没有空格,相邻结点之间用一个空格隔开。每棵树的输入用一对空括号“()”结束(这对括号本身不代表一个结点)
如果从根到某个叶结点的路径上有的结点没有在输入中给出,或者给出超过一次,应当输出-1。
个人认为此题的难点在于字符串的处理,其实也不难。
然后就是根据字符串建树,建好树bfs即可。
这里给出数组和链表两种写法。
代码
使用数组
string s;const int root = 1;int Left[maxn], Right[maxn], cnt;int val[maxn];void init() { met(val, 0); Left[root] = Right[root] = 0; cnt = root;}int newnode() { int u = ++cnt; Left[u] = Right[u] = 0; return u;}bool check() { queue<int> q; q.push(root); while(!q.empty()) { int t = q.front();q.pop(); if(val[t] == 0) return false; if(Left[t] != 0) q.push(Left[t]); if(Right[t] != 0) q.push(Right[t]); } return true;}void ot() { queue<int> q; q.push(root); bool spc = 0; while(!q.empty()) { int t = q.front(); q.pop(); if(spc) cout << " "; if(!spc) spc = 1; cout << val[t]; if(Left[t] != 0) q.push(Left[t]); if(Right[t] != 0) q.push(Right[t]); } cout << endl;}int main() { #ifdef _LOCAL IN; #endif // _LOCAL init(); bool flag = 1; while(cin >> s) { if(s == "()") { if(check() && flag ) ot(); else printf("not complete\n"); flag = 1; init(); continue; } int pos = s.find(','), a; string s1 = s.substr(1,pos-1); stringstream ss(s1); ss >> a; string s2 = s.substr(pos+1, s.size()-2-pos); int len = s2.size(); int cur = root; for(int i = 0; i < len; ++i) { if(s2[i] == 'L') { if(Left[cur] == 0) Left[cur] = newnode(); cur = Left[cur]; } else { if(Right[cur] == 0) Right[cur] = newnode(); cur = Right[cur]; } } if(val[cur] != 0) flag = 0; val[cur] = a; } return 0;}
使用链表
string s;struct node { int val; node *Left, *Right; node():val(0), Left(NULL), Right(NULL){}};node* root;queue<node* > freeNodes; //内存池node Node[maxn];void init() { for(int i = 0; i < maxn; ++i) freeNodes.push(&Node[i]);}node* newnode() { node* u = freeNodes.front(); u->val = 0; u->Left = u->Right = NULL; freeNodes.pop(); return u;}void Delete(node* u) { freeNodes.push(u);}bool check() { queue<node> q; q.push(*root); while(!q.empty()) { node t = q.front();q.pop(); if(t.val == 0) return false; if(t.Left != NULL) q.push(*t.Left); if(t.Right != NULL) q.push(*t.Right); } return true;}void ot() { queue<node> q; q.push(*root); bool spc = 0; while(!q.empty()) { node t = q.front(); q.pop(); if(spc) cout << " "; if(!spc) spc = 1; cout << t.val; if(t.Left != NULL) q.push(*t.Left); if(t.Right != NULL) q.push(*t.Right); } cout << endl;}int main() { #ifdef _LOCAL IN; #endif // _LOCAL init(); root = newnode(); bool flag = 1; while(cin >> s) { if(s == "()") { if(check() && flag ) ot(); else printf("not complete\n"); flag = 1; root = newnode(); continue; } int pos = s.find(','), a; string s1 = s.substr(1,pos-1); stringstream ss(s1); ss >> a; string s2 = s.substr(pos+1, s.size()-2-pos); int len = s2.size(); node *cur = root; for(int i = 0; i < len; ++i) { if(s2[i] == 'L') { if(cur->Left == NULL) cur->Left = newnode(); cur = cur->Left; } else { if(cur->Right == NULL) cur->Right = newnode(); cur = cur->Right; } } if(cur->val != 0) flag = 0; cur->val = a; } Delete(root); return 0;}
UVA-548 - Tree
思路
给一棵点带权(权值各不相同,都是小于10000的正整数)的二叉树的中序和后序遍历,找一个叶子使得它到根的路径上的权和最小。如果有多解,该叶子本身的权应尽量小。输入中每两行表示一棵树,其中第一行为中序遍历,第二行为后序遍历。
由中序和后序建树即可。建好树题目就水的不行了。
代码
int in[maxn], po[maxn], a, ans, ax;int Left[maxn], Right[maxn], root;int build(int L1, int R1, int L2, int R2) { //if(L1 == R1) ans = min(ans, in[L1]); if(L1 > R1) return 0; int rt = po[R2]; int p = L1; while(in[p] != rt) ++p; Left[rt] = build(L1, p-1, L2, L2 + p-L1 -1); Right[rt] = build(p+1,R1, L2 + p-L1, R2-1); return rt;}void dfs(int x, int val) { if(Left[x] == 0 && Right[x] == 0) { if(ans > val) ans = val, ax = x; else if(ans == val && x < ax) ans = val, ax = x; return; } if(Left[x] > 0) dfs(Left[x], val +Left[x]); if(Right[x] > 0) dfs(Right[x], val + Right[x]);}int main() { #ifdef _LOCAL IN; #endif // _LOCAL string s; while(getline(cin, s)) { met(Left, 0); met(Right, 0); stringstream ss(s); int idx = 0, idy = 0; while(ss >> a) in[++idx] = a; getline(cin, s); stringstream sss(s); while(sss >> a) po[++idy] = a; root = build(1, idx, 1, idy); ans = INF, ax = INF; dfs(root, root); cout << ax <<endl; } return 0;}
UVA-839 - Not so Mobile
思路
这两题和二叉树本身并无太深的联系,主要是递归输入,有一种二叉树的思想在里面。
代码
const int root = 1;int Left[maxn], Right[maxn], cnt;int W[maxn], D[maxn];bool flag = 1;void init() { met(Left, 0); met(Right, 0); Left[root] = Right[root] = 0; cnt = root; flag = 1;}int newnode() { int u = ++cnt; Left[u] = Right[u] = 0; return u;}int read(int rt) { int a, b, c, d; scanf("%d%d%d%d", &a, &b, &c, &d); if(Left[rt] == 0) Left[rt] = newnode(); if(Right[rt] == 0) Right[rt] = newnode(); D[Left[rt]] = b, D[Right[rt]] = d; if(a == 0) a = read(Left[rt]); if(c == 0) c = read(Right[rt]); W[Left[rt]] = a, W[Right[rt]] = c; W[rt] = a + c; if(a*b != c*d) flag = 0; return W[rt];}int main() { #ifdef _LOCAL IN; #endif // _LOCAL int t; cin >> t; while(t--) { init(); read(root); if(flag) printf("YES\n"); else printf("NO\n"); if(t) printf("\n"); } return 0;}
UVA-699 - The Falling Leaves
思路
同样是考查递归输入的水题。
代码
bool read(int id) { int a; scanf("%d", &a); if(a == -1) return false; read(id-1); read(id+1); ans[id]+=a; return true;}int main() { #ifdef _LOCAL IN; #endif // _LOCAL int kase = 0; met(ans, 0); while(read(maxn/2)) { aid = maxn/2; cnt = 0, cnt2 = 0; while(ans[aid]!=0) --aid; ++aid; //bfs(); printf("Case %d:\n", ++kase); printf("%d", ans[aid]); for(int i = aid+1; ans[i]!=0; ++i) printf(" %d", ans[i]); printf("\n\n"); met(ans, 0); } return 0;}
UVA-297 - Quadtrees
思路
这一题叫做四分树。实际上和二叉树没多大区别。
注意最大层数为5层。
代码
char s1[maxn], s2[maxn];int id, deep;const int root = 1;int Left[maxn], Right[maxn], Up[maxn], Down[maxn], cnt;int val[maxn];void init() { Left[root] = Right[root] = Up[root] = Down[root] = 0; cnt = root; met(val, 0);}int newnode() { int u = ++cnt; Left[u] = Right[u] = Up[u] = Down[u] = 0; return u;}void build(char s[], int rt, int depth) { //deep = max(deep, depth); if(s[id] == 'f') { if(val[rt] == 0) val[rt] = 1; Left[rt] = Right[rt] = Up[rt] = Down[rt] = 0; } else if(s[id] == 'e') {} else { if(val[rt] == 1) return; if(Left[rt] == 0) Left[rt] = newnode(); ++id; build(s, Left[rt], depth+1); if(Right[rt] == 0) Right[rt] = newnode(); ++id; build(s, Right[rt], depth+1); if(Up[rt] == 0) Up[rt] = newnode(); ++id; build(s, Up[rt], depth+1); if(Down[rt] == 0) Down[rt] = newnode(); ++id; build(s, Down[rt], depth+1); }}int solve() { int ans = 0; queue<int> q, d; q.push(root); d.push(0); while(!q.empty()) { int t = q.front(); q.pop(); int dp = d.front(); d.pop(); if(val[t] == 1) ans += pow(4,deep-dp); if(Left[t] != 0) q.push(Left[t]), d.push(dp+1); if(Right[t] != 0) q.push(Right[t]), d.push(dp+1); if(Up[t] != 0) q.push(Up[t]), d.push(dp+1); if(Down[t] != 0) q.push(Down[t]), d.push(dp+1); } return ans;}int main() { #ifdef _LOCAL IN; #endif // _LOCAL int t; cin >> t; while(t--) { deep = 5;init(); scanf("%s%s",s1, s2); id = 0; build(s1, root, 0); id = 0; build(s2, root, 0); //cout << deep <<endl; printf("There are %d black pixels.\n", solve()); } return 0;}
自己的代码略水,书上的代码好。如下:
#include<cstdio>#include<cstring>const int len = 32;const int maxn = 1024 + 10;char s[maxn];int buf[len][len], cnt;//把字符串s[p..]导出到以(r,c)为左上角,边长为w的缓冲区中//2 1//3 4void draw(const char* s, int& p, int r, int c, int w) { char ch = s[p++]; if(ch == 'p') { draw(s, p, r, c+w/2, w/2); //1 draw(s, p, r, c , w/2); //2 draw(s, p, r+w/2, c , w/2); //3 draw(s, p, r+w/2, c+w/2, w/2); //4 } else if(ch == 'f') { //画黑像素(白像素不画) for(int i = r; i < r+w; i++) for(int j = c; j < c+w; j++) if(buf[i][j] == 0) { buf[i][j] = 1; cnt++; } }}int main( ) { int T; scanf("%d", &T); while(T--) { memset(buf, 0, sizeof(buf)); cnt = 0; for(int i = 0; i < 2; i++) { scanf("%s", s); int p = 0; draw(s, p, 0, 0, len); } printf("There are %d black pixels.\n", cnt); } return 0;}
- 入门经典_Chap06_例题[二]:二叉树的指针及数组实现
- 入门经典_Chap06_例题[一]:队列,栈,链表的数组实现
- 入门经典_Chap06_例题[三]:图的搜索 Floodfill 拓扑排序 欧拉回路
- 入门经典_Chap06_例题[四]:最后四题
- 入门经典_Chap06_习题:搜索 数据结构 欧拉回路
- 算法竞赛入门经典第6章例题(2):二叉树部分+四分树
- 指针经典例题
- 指向数组的指针例题小析
- 后缀数组经典例题
- 数组与指针例题
- 指针数组例题分析
- 指针数组 例题
- C经典例题二
- 二叉树的数组实现
- 二维数组的排列以及二维数组与指针例题
- 二叉树学习(二):二叉树的基本操作及代码实现
- 算法入门经典--二叉树
- 算法竞赛入门 刘汝佳 例题代码及练习题代码(二)
- 安卓开发进阶之弹性布局FlexboxLayout--Part2(翻译)
- centOS7.0上安装使用zookeeper环境
- 小学期链表作业
- bzoj 1799: [Ahoi2009]self 同类分布 (数位DP)
- CodeVS 1215 迷宫 题解
- 入门经典_Chap06_例题[二]:二叉树的指针及数组实现
- webrtc编译arm版本
- 【数据压缩】H.264编码
- 【Python那些事儿】数据放缩
- [leetcode]576. Out of Boundary Paths
- Git submodule (1)
- Windows下Mysql5.7忘记root密码的解决方法
- 虫子爬进问题
- juc--CopyOnWriteArraySet