Tree Summing (二叉搜索树的输入处理)

    LISP was one of the earliest high-level programming languages and, with FORTRAN, is one of the oldest languages currently being used. Lists, which are the fundamental data structures in LISP, can easily be adapted to represent other important data structures such as trees.

    This problem deals with determining whether binary trees represented as LISP S-expressions possess a certain property.

    Given a binary tree of integers, you are to write a program that determines whether there exists a root-to-leaf path whose nodes sum to a specified integer.

    For example, in the tree shown on the right there are exactly four root-to-leaf paths. The sums of the paths are 27, 22, 26, and 18. Binary trees are represented in the input file as LISP S-expressions having the following form.

    empty tree ::= ()

    tree ::= empty tree | (integer tree tree)

    The tree diagrammed above is represented by the expression

(5 (4 (11 (7 () ()) (2 () ()) ) ()) (8 (13 () ()) (4 () (1 () ()) ) ) )

    Note that with this formulation all leaves of a tree are of the form (integer () () )

    Since an empty tree has no root-to-leaf paths, any query as to whether a path exists whose sum is a specified integer in an empty tree must be answered negatively.

Input

The input consists of a sequence of test cases in the form of integer/tree pairs. Each test case consists of an integer followed by one or more spaces followed by a binary tree formatted as an S-expression as described above. All binary tree S-expressions will be valid, but expressions may be spread over several lines and may contain spaces. There will be one or more test cases in an input file, and input is terminated by end-of-file.

Output

There should be one line of output for each test case (integer/tree pair) in the input file. For each pair I, T (I represents the integer, T represents the tree) the output is the string ‘yes’ if there is a root-to-leaf path in T whose sum is I and ‘no’ if there is no path in T whose sum is I.

Sample Input

22 (5(4(11(7()())(2()()))()) (8(13()())(4()(1()()))))

20 (5(4(11(7()())(2()()))()) (8(13()())(4()(1()()))))

10 (3

         (2 (4 () () )

             (8 () () ) )

        (1 (6 () () )

            (4 () () ) ) )

5 ()

Sample Output

yes

no

yes

no

题意:给了一个整数n,和一棵搜索树的前序遍历结果。规定 (integer (a) (b) ) integer的左儿子为a,右儿子为b。()表示空树。求从根到各个叶的和有没有等于n的路径。

思路:这道题看似十分麻烦,但只要理解题意后,合理处理输入就简单了。由于输入中含有没有用的空格且存在于多行,因此我们可以采取一个字符一个字符的输入。当形成一颗完整的树时 n( '(' ) == n( ')' )输入结束。处理完输入后,我们可以通过字符串处理算出每一个节点的值(可能含有负数),规定没有节点的地方用 inf 处理。我们可以用一个队列来储存每一个节点的值,这样我们就得到了一个完整的(含有叶节点的儿子)的前序遍历结果。我们将结果依次从队列中取出,根据前序遍历顺序来建树如果遇到 inf 则表示这个节点为空,返回上一个节点求右儿子。因此我们可以根据这个遍历结果构建一颗完整的二叉树,从而可以求出根节点到每一个叶节点的和,判断是否存在和n相等的树。

代码如下:

#include<cstdio>
#include<cstring>
#include<queue>
#include<stack>
#include<vector>
#define inf 0x3f3f3f3f
using namespace std;
int n,flag;
queue<int>Q;
struct node
{
    int val;
    node *lch,*rch;
};
node *insertt(node *root)
{
    int x=Q.front(); //获得队首的值
    Q.pop();
    if(x==inf) //表示这个节点为空,直接返回上一个节点
    {
        root=NULL;
        return root;
    }
    node *q = new node; //声明一个动态空间的指针
    q->val=x;           //前序遍历,先根,,因此先赋值
    q->lch=q->rch=NULL;  //根的左右儿子赋值为空
    q->lch=insertt(q->lch); //递归处理左儿子
    q->rch=insertt(q->rch); //递归处理右儿子
    return q;    //返回此节点的地址
}
int check(node *root,int sum)
{
    if(root!=NULL)  //此节点不为空
    {
        int x=check(root->lch,sum+root->val);//递归带入节点和
        int y=check(root->rch,sum+root->val);
        if(x+y==2) //左右节点都为空,即这个点是叶节点
        {
            if(sum+root->val==n) //判断是否和n相等
                flag=1;
        }
        return 0;
    }
    else  //此节点为空
        return 1;
}
int main()
{
    while(~scanf("%d",&n))  //输入n
    {
        flag=0;
        //getchar();
        while(!Q.empty())  //清空队列
            Q.pop();
        int l=0,r=0;     //左右括号的数量初始化为0
        char c;
        vector<char>str;  //建立一个vector数组,用来存放处理过的字符串
        while(scanf("%c",&c))  //每次吸收一个字符
        {
            if((c>='0'&&c<='9')||c=='('||c==')'||c=='-')  //去除空格和换行符
            {
                str.push_back(c);  //添加到str数组后面
                if(c=='(')    //左括号数量+1
                    l++;
                else if(c==')')//右括号数量+1
                    r++;
                if(l==r)  //左右括号数量一致,说明已经构建成了一颗树,结束输入
                    break;
            }
        } //此时我们就已经将多行的数据变成了一行
        for(int lx=0; lx<str.size(); lx++) //从第一个开始处理
        {
            if(str[lx]=='(') //如果遇到左括号,就代表遇到了一个值
            {
                int x=0,y=0,z=0;
                for(++lx; lx<str.size(); lx++)
                    if(str[lx]=='-') //值为负数
                        z=1;
                    else if(str[lx]>='0'&&str[lx]<='9')//求值的大小
                    {
                        y++;    //记录位数
                        x=x*10+str[lx]-'0';
                    }
                    else
                        break;
                if(y==0) //如果位数位为0,说明这是一个空节点,赋为inf
                    Q.push(inf);
                else
                {
                    if(z)  //如果是负数,加上负号
                        x=-x;
                    Q.push(x);
                }
                lx--;//可能遇到(a( 的情况,因此要减一下,下次仍然处理这个字符
            }
        }
        node *root=NULL; //定义一个空的结构体指针
        root=insertt(root); //递归建树
        int x=check(root,0);//检查有没有和n相等的路径和
        if(flag)
            printf("yes\n");
        else
            printf("no\n");
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值