UVA548

一道很好的练习树的题目;

值的总结的地方有:
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开始)

转载于:https://www.cnblogs.com/TorettoRui/p/10432567.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值