简体   繁体   English

在C ++中从s表达式构造二叉树

[英]Construct binary tree from s-expression in c++

empty tree ::= ()
tree ::= empty tree | (w tree tree)
ex:
()
empty tree

(99(5()())(35(-5()())()))

     99
    /  \
   5   35
      /
     -5

class Node
{
public:
    int weight; // weight can be negative!
    Node *left, *right;
    Node():weight(0),left(NULL),right(NULL){}
    Node(int d):weight(d),left(NULL),right(NULL){}
};

Construct a binary tree by given condition 根据给定条件构造二叉树

I get problem with construct it, my program will crush and I have no idea about why it happened, the following is my code and I print out some information for debug, take (99(5()())(35(-5()())())) as a test case, it will print out 99(5( and crush, I think maybe problem is at which I deal with ) where I return node which is NULL, but I can't find problem with it. By the way, this tree is expected to handle HUNDREDS of nodes in each tree, and Each of the test cases contains up to TEN-THOUSAND trees, will I run out of time with this program or what should I need to do?Thank for your time 我在构造它时遇到问题,我的程序将崩溃,我不知道为什么会发生,以下是我的代码,我打印出一些信息进行调试,请使用(99(5()())(35(-5 ()())()))作为测试用例,它将打印出99(5(然后暗恋,我认为可能是我处理的问题),其中我返回的节点为NULL,但我找不到顺便说一句,这棵树有望处理每棵树中的数百个节点,并且每个测试用例最多包含一万棵树,我会在这个程序上用完时间还是需要什么?谢谢你的时间

Node* MyBinaryTreeOps::constructTree(Node *root, std::string treeStr)const
{
    int idex = 1;//always look at the treeStr[1]
    Node *cur=NULL;//use to pass in recursive call
    if(treeStr[idex]!='('&&treeStr[idex]!=')'){//meet number create new node
       stringstream ss;
       while(treeStr[idex]!='('){
             ss<<treeStr[idex];
             if(treeStr.size()>1){//if size > 1 then remove the treeStr[1],to let treeStr[1] become next char in treeStr
                treeStr.erase(1,1);
             }
        }
        int num=0;
        ss>>num;
        std::cout<<num<<std::endl;//print out just for debug
        std::cout<<treeStr[idex]<<std::endl;//print out just for debug
        root = new Node(num);
     }

    if(treeStr[idex]==')'){//meet ')' return subtree constructed
      if(treeStr.size()>1){
         treeStr.erase(1,1);
      }
       return root;
    }
    if(treeStr[idex]=='('){//meet first '(' then construct left subtree
       if(treeStr.size()>1){
          treeStr.erase(1,1);
       }

       root->left = constructTree(cur,treeStr);

    }

    if(treeStr[idex]=='('){ //meet second '(' then construct right subtree
       if(treeStr.size()>1){
          treeStr.erase(1,1);
       }
       root->right = constructTree(cur,treeStr);

    }
    if(treeStr[idex]==')'){ //meet ')' return subtree constructed
       if(treeStr.size()>1){
          treeStr.erase(1,1);
       }
       return root;
    }
}

I've tried this problem by myself and this is the function that I've wrote. 我自己尝试了这个问题,这就是我编写的功能。

Steps of the algorithm: 算法步骤:

  1. Find a part of the sequence that represents weight of current node. 找到代表当前节点权重的序列的一部分。 Convert it to int and assign to node. 将其转换为int并分配给node。
  2. Slice string to remove weight, starting and ending brace. 切细绳子以减轻重量,开始和结束支撑。
  3. Iterate over sequence to find point between two braces that divides children nodes. 遍历序列以找到两个划分子节点的花括号之间的点。
  4. Split children string into two sequences (We can slice starting tree and reuse it as sequence of one of the children nodes). 将子字符串分割成两个序列(我们可以对起始树进行切片,并将其作为子节点之一的序列重用)。
  5. If child node has weight (length of its sequence is larger than 2) then create new node and recurse algorithm. 如果子节点具有权重(其序列的长度大于2),则创建新节点并递归算法。

Additionally, here is my program with some test examples and a little bit extended Node class: 此外,这是我的程序,其中包含一些测试示例和一些扩展的Node类:

Node* constructTree(Node* root, std::string& treeString) {
    // Find the weight of this node.
    auto weightLeft = treeString.find_first_of("(") + 1;
    auto weightRight = treeString.find_first_of("()", weightLeft);
    auto weightString = treeString.substr(weightLeft, weightRight - weightLeft);

    // Optional, we check if there is any weight, if there is not we leave zero
    // weight from constructor.
    // Works for something like that: ((1)(2)) -> (0(1)(2))
    if (weightString.length() > 0) {
        root->weight = std::stoi(weightString);
    }

    // Slice string to contain only children sequences.
    treeString.erase(0, weightRight);
    treeString.erase(treeString.length() - 1, 1);

    // Looking for index in string where a left child ends and a right child starts.
    // This point(index) is located where count of left braces and for braces
    // is the same and the counts are not zero.
    int splitPoint = -1;
    int leftBraces = 0, rightBraces = 0;
    for (int index = 0; index < treeString.length(); index++) {
        char c = treeString[index];
        if (c == '(') {
            ++leftBraces;
        }
        if (c == ')') {
            ++rightBraces;
        }

        if (leftBraces == rightBraces) {
            splitPoint = index + 1;
            break;
        }
    }

    // If split point has been found then it means that this node has children.
    if (splitPoint != -1) {
        auto leftChildString = treeString.substr(0, splitPoint);
        auto rightChildString = treeString.erase(0, splitPoint);

        // Check for length so construct will stop if there is no child.
        if (leftChildString.length() > 2) {
            root->left = new Node();
            constructTree(root->left, leftChildString);
        }

        if (rightChildString.length() > 2) {
            root->right = new Node();
            constructTree(root->right, rightChildString);
        }
    }

    return root;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM