一道很好的练习树的题目;
值的总结的地方有:
1》如果想要查看自己的树建立的是否正确,那么就输出这棵树的前序遍历和中序遍历,注意在遍历的时候判断一下各子树是否存在,如果存在,才可以进去遍历。和dfs的思想是一致的
2》虽然是使用数组的方式实现二叉树,但是newnode()函数也还是不可缺少的。因为这个函数将新“申请”到的节点给初始化了。
3》此题的输入输出框架总结。这道题就是我之前提过的一行的长度不确定,而且必须是输入数字的,那么这个时候就踏踏实实的使用sstream吧。当不是输入数字,或者一行中输入少量的数字,那么这个时候可以考虑使用c_str()函数来转换一下。
4》然后就是最终要的递归了。
首先来看递归建树的部分(建树不一定要使用递归):递归建树很好的使用了递归的思想,那就是 分治,结合,先分治再结合,这就是递归的精髓。
在使用递归的时候,要做好不能分治的准备,然后再去判断是否能够分治。
在计算最后的权值的时候,也是利用的递归的思想。
假如只要求求出最小的和的话,那么递归程序将是这样的 1:算出左子树的sum 2,算出右子树的sum 3 看那个sum小,就是这棵树的sum
但是这道题不能这么做,因为还需要直到对应的叶子。那么就可以这样 1 算出左子树的sum以及对于的叶子值,2 算出右子树的sum以及对应的叶子值,3,比较sum和叶子值。如代码中的compute2()函数。
这就是完全递归的思想
先把代码贴上来吧,一会再分析:
//这道目是一道很的锻炼递归的题目,也是有一道使用数组来构造二叉树的题目 //分治,结合,就是递归的思想 //需要总结的地方,第一递归如何做的,第二两种建树的方式,第三如何验证建树的正确性,第四newnode是如何做的,第五输入的框架 #include<cstdio> #include<string> #include<cstring> #include<sstream> #include<iostream> using namespace std; int inorder[10000 + 5]; int postorder[10000 + 5]; int Node[10000 + 5]; int Left[10000 + 5]; int Right[10000 + 5]; int cnt = 1,len; int best_value,best_sum; int new_node() { Node[cnt] = 0; Left[cnt] = 0; Right[cnt] = 0; return cnt++; } //在中序的start和last中间找到x int find(int start,int last,int x) { for(int i = start;i <= last; i++) { if(inorder[i] == x) { return i; } } } //两种不同的建树方案,一种是递归建树,一种是先得到根节点,再一步一步建树 int creat_tree1(int in_start, int in_last,int post_start,int post_last) { if(in_start > in_last) { return 0;//只有一个节点的下一层 } int root = new_node(); Node[root] = postorder[post_last]; int pos = find(in_start,in_last,postorder[post_last]); Left[root]=creat_tree1(in_start,pos - 1,post_start,post_start + pos - 1 - in_start); Right[root]=creat_tree1(pos + 1,in_last,post_last - 1 - (in_last - pos - 1),post_last - 1); return root; } int creat_tree2(int in_start, int in_last,int post_start,int post_last) { printf("%d %d %d %d\n",in_start,in_last,post_start,post_last); if(in_start == in_last) { int root = new_node(); Node[root] = inorder[in_start]; return root; } int pos = find(in_start,in_last,postorder[post_last]); int left = 0, right = 0; if(pos>in_start) { left=creat_tree2(in_start,pos - 1,post_start,post_start + pos - 1 - in_start); } if(pos<in_last) { right=creat_tree2(pos + 1,in_last,post_last - 1 - (in_last - pos - 1),post_last - 1); } int root = new_node(); Left[root] = left; Right[root] = right; Node[root] = inorder[pos]; return root; } bool read_in_post(int* A) { len = 0; string line; if(!(getline(cin,line))) return false; stringstream ss(line); while(ss>>A[len]) { len++; } return true; } void front_order(int root) { printf("%d ",Node[root]); if(Left[root]) front_order(Left[root]); if(Right[root]) front_order(Right[root]); } void in_order(int root) { if(Left[root]) in_order(Left[root]); printf("%d ",Node[root]); if(Right[root]) in_order(Right[root]); } void print_tree(int root) { front_order(root); printf("\n"); in_order(root); printf("\n"); } void compute1(int root,int &sum, int &value) { int left_sum = 200000000; int left_value = 200000000; int right_sum = 200000000; int right_value = 200000000; if(!Left[root]&&!Right[root])//叶子节点 { sum = Node[root]; value = Node[root]; return; } if(Left[root]) { compute1(Left[root],left_sum,left_value); } if(Right[root]) { compute1(Right[root],right_sum,right_value); } if((left_sum < right_sum)||(left_sum==right_sum && left_value < right_value)) { value = left_value; sum = left_sum + Node[root]; return; } else { value = right_value; sum = right_sum + Node[root]; } } //这个也应该是分治,结合的思想 void compute2(int root,int sum) { sum = sum + Node[root]; if(Left[root]) compute2(Left[root],sum); if(Right[root]) compute2(Right[root],sum); if(!Left[root]&&!Right[root]) { if(sum < best_sum || (sum == best_sum && Node[root] < best_value)) { best_value = Node[root]; best_sum = sum; } } } void print_in() { for(int i=0;i<len;i++) { printf("%d ",inorder[i]); } printf("\n"); } void print_post() { for(int i=0;i<len;i++) { printf("%d ",postorder[i]); } printf("\n"); } int main() { #ifdef local freopen("input.txt","r",stdin); //freopen("output.txt","w",stdout); #endif while(read_in_post(inorder)) { cnt = 1; read_in_post(postorder); int root = creat_tree2(0,len-1,0,len-1); print_tree(root); best_value = 100000; best_sum =200000000; compute1(root,best_sum,best_value); printf("%d\n",best_value); } return 0; }
在这道题目中犯过两个错误,第一个是栈溢出了,这个是因为递归调用的函数太多了一点
第二个是因为节点编号是从0开始的。所以以后树的节点编号一律从1开始。(链表的头节点可以从0开始)