Vijos1114解题报告(不建树解决二叉树问题)
2015-03-29 11:49
405 查看
描述:
我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。
FBI树是一种二叉树1,它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2^N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:
1) T的根结点为R,其类型与串S的类型相同;
2) 若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。
现在给定一个长度为2^N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历2序列。
解题思路:使用函数求出每个节点,然后通过该节点构建树,最后遍历树即可。
难点:建树函数void buildtree(int start, int end, treeNode* &root) 当start与end相等时,如果递归参数不当,如构建左子树使用函数buildtree(start, (start+end)/2, root->lc),会陷入无限递归的深渊。
处理方法:
1:求串的左半边时用(start+end+1)/2-1;求右半边用(start+end)/2+1, 构建函数最开始用判断条件start>end时return;
2: 构建函数在递归调用前判断start是否等于end如果等于不递归调用函数;
代码:
优化:
上面的方法过于麻烦:
其实由于树是先序建立的,所以如果建立根结点后,递归建立左子树和右子树前就把节点的值输出,那么树建立结束的同时就输出树的先序遍历序列。如果在建立左右子树后再输出节点的值,那么最后输出了树后序遍历序列。如果在建立左子树后,建立右子树前输出节点的值,那么最后输出了树的后序遍历序列。
只要符合先序建树的条件就可以用这种方法。
这样以来就不用保存树的节点,也不用在遍历树了。减少了时间复杂度和空间复杂度。
代码如下:
使用处理方法1:
进一步优化:
在求每个节点时,其实不用重新遍历串了,只需根据该节点左右孩子就可以确定该节点是F还是B还是I。如果左右节点不同,该节点为F,否则该节点和其左右节点相同。这样时间复杂度会进一步降低,代码如下:
我们可以把由“0”和“1”组成的字符串分为三类:全“0”串称为B串,全“1”串称为I串,既含“0”又含“1”的串则称为F串。
FBI树是一种二叉树1,它的结点类型也包括F结点,B结点和I结点三种。由一个长度为2^N的“01”串S可以构造出一棵FBI树T,递归的构造方法如下:
1) T的根结点为R,其类型与串S的类型相同;
2) 若串S的长度大于1,将串S从中间分开,分为等长的左右子串S1和S2;由左子串S1构造R的左子树T1,由右子串S2构造R的右子树T2。
现在给定一个长度为2^N的“01”串,请用上述构造方法构造出一棵FBI树,并输出它的后序遍历2序列。
解题思路:使用函数求出每个节点,然后通过该节点构建树,最后遍历树即可。
难点:建树函数void buildtree(int start, int end, treeNode* &root) 当start与end相等时,如果递归参数不当,如构建左子树使用函数buildtree(start, (start+end)/2, root->lc),会陷入无限递归的深渊。
处理方法:
1:求串的左半边时用(start+end+1)/2-1;求右半边用(start+end)/2+1, 构建函数最开始用判断条件start>end时return;
2: 构建函数在递归调用前判断start是否等于end如果等于不递归调用函数;
代码:
#include <cstdio> #include <cstring> #include <cmath> const int MAXN = 2000; char str[MAXN]; int nodenum; class treeNode { public: treeNode *lc; treeNode *rc; char c; }; char findRoot(int start, int en) { if(start > en) return 'N'; int i; char first = str[start]; for(i=start; i <= en; i++) { if(str[i] != first) return 'F'; } if(first == '0') return 'B'; return 'I'; } void buildtree(int start, int end, treeNode* &root) { if(start > end) { root = NULL; return; } char rootc; rootc = findRoot(start, end); root = new treeNode; root->c = rootc; buildtree(start,(start + end + 1) / 2-1, root->lc); buildtree((start + end) / 2+1, end, root->rc); } void lvisit(treeNode *root) { if(root == NULL) return; lvisit(root->lc); lvisit(root->rc); printf("%c", root->c); } int main() { scanf("%d", &nodenum); scanf(" %s", str); nodenum = pow(2, nodenum); treeNode *root = NULL; buildtree(0, nodenum-1, root); lvisit(root); printf("\n"); }
优化:
上面的方法过于麻烦:
其实由于树是先序建立的,所以如果建立根结点后,递归建立左子树和右子树前就把节点的值输出,那么树建立结束的同时就输出树的先序遍历序列。如果在建立左右子树后再输出节点的值,那么最后输出了树后序遍历序列。如果在建立左子树后,建立右子树前输出节点的值,那么最后输出了树的后序遍历序列。
只要符合先序建树的条件就可以用这种方法。
这样以来就不用保存树的节点,也不用在遍历树了。减少了时间复杂度和空间复杂度。
代码如下:
使用处理方法1:
#include <cstdio> #include <cstring> #include <cmath> const int MAXN = 1050; char str[MAXN]; int nodenum; char findRoot(int start, int en) { while(start<en) { if(str[start] != str[en]) return 'F'; start++; } if(str[en] == '0') return 'B'; return 'I'; } void buildtree(int start, int end) { if(start > end) return; buildtree(start,(start + end + 1) / 2-1); buildtree((start + end) / 2+1, end); printf("%c", findRoot(start, end)); } int main() { scanf("%d", &nodenum); scanf(" %s", str); buildtree(0, pow(2, nodenum)-1); printf("\n"); }
进一步优化:
在求每个节点时,其实不用重新遍历串了,只需根据该节点左右孩子就可以确定该节点是F还是B还是I。如果左右节点不同,该节点为F,否则该节点和其左右节点相同。这样时间复杂度会进一步降低,代码如下:
#include <cstdio> #include <cstring> #include <cmath> const int MAXN = 1025; char str[MAXN]; int nodenum; char buildtree(int start, int end) { char a; if(start != end) { a = buildtree(start,(start + end)/2); if(a!= buildtree((start + end)/2+1, end)) a = 'F'; printf("%c", a); return a; } if(str[start] == '0') a = 'B'; else a = 'I'; printf("%c", a); return a; } int main() { scanf("%d", &nodenum); scanf(" %s", str); buildtree(0, pow(2, nodenum)-1); printf("\n"); }
相关文章推荐
- hdoj 1207(解决n=64问题)解题报告
- LeetCode: Spiral Matrix II 解题报告-三种方法解决旋转矩阵问题
- 解决asp报告“库没有注册”的问题
- 新版Blog问题解决报告2007.02.07
- POJ 2756 二叉树 解题报告
- 智力题解题报告 No.1 玛丽莲问题-宝马与马
- FOJ--1698--最大乘积--解题报告(大数乘小数的问题)
- 日志在2003上报告 security 问题的解决办法
- POJ 2692 假币问题 解题报告
- POJ 2746 约瑟夫问题 解题报告
- NIT-OJ-1449-最少硬币问题-解题报告
- 新版Blog问题解决报告2007.02.07
- acm pku 2234 解题报告(取子问题)
- .net问题:尝试打开web项目,web服务器报告以下错误:http/1.1 500 Internal server error,请问该怎么解决这个问题??
- POJ 2811 熄灯问题 解题报告
- [dp问题] Poj 1014 & Zoj 1149 (Dividing) 解题报告(转)
- acm pku 1321解题报告 棋盘问题
- NOI 1192 加分二叉树 解题报告
- pku 1321 深搜 棋盘问题 解题报告
- 解决打开WORD错误报告问题