-1
Node * create(Node * root, int I, int J, string str)
{
    if (I == J) { root -> data =str[I]; root -> left=NULL; root -> right=NULL; }
    int i = 0, j = 0, k = 0, l = 0;

    //// to store the data of root
    string val;
    for (i = I; i < J; i++) {

        if (str[i] == '(') break;
        val.push_back(str[i]);


    }
    root -> data = stoi(val);
    stack < char > st;
    for (j = i; j < J; j++) {
        if (str[j] == '(') st.push(str[j]);
        else if (str[j] == ')') st.pop();
        if (st.empty()) break;
    }

    for (l = j + 1; l < J; l++) {
        if (str[l] == '(') st.push(str[l]);
        else if (str[l] == ')') st.pop();
        if (st.empty()) break;
    }
    k = j + 1;



    if (j - i == 2) root -> left -> data = str[i + 1];
  else
    root -> left =  create(root -> left, i + 1, j - 1, str);
    if (l == k) root -> right=NULL;
  else if (l - k == 2) root -> right -> data = str[k + 1];
  else
    root -> right =  create(root -> right, k + 1, l - 1, str);

    return root;
}
Node * treeFromString(string str){
    Node * p = create(p, 0, str.size() - 1, str);
    return p;

}

Here I have initialized variables i , j , k , l to track the left child and right child bracket in the string. I , J are the range of the node for a particular activation record of recursion.

  • [Here's how to ask a proper "Where's the bug / Fix my code" question](https://meta.stackoverflow.com/a/253788/11107541). Can you please read it and apply what you learn to improve your question? You can also read [ask] for further guidance. As instructed in [ask], please describe your problem _before_ showing code. – starball Jan 06 '23 at 07:58
  • Why do you have both `root->data=str[I]` and `root->data=stoi(val)`?? What is the data type of `data`? It makes little sense to sometimes assign a character (code) and sometimes an integer value... In my IDE this code gives lots of warnings... Please include the `Node` class in your question. – trincot Jan 06 '23 at 10:53

2 Answers2

1

I assume you parsed some expression, by your code I pre-implemented it.

I just implement build a tree for following expression:

expression:  |<symbol>| <integer> '(' <expression> ')' '('<expression>')'
symbol : any C++ `char` single byte character.
integer : any C++ valid int type value.

#include <iostream>
#include <string>
#include <string_view> // C++17 std::string_view
#include <charconv>  // C++17  std::from_chars.
#include <cassert>

//simulate Node class
struct Node
{
    Node *left, *right;
    int data;
};

 //1. use string_view  instead of triple I, J, std::string.
 //2. First argument Node* root - needn't. It should be local variable.
Node * create(std::string_view str)
{
    assert(!str.empty());
    
    if (str.size() == 1) 
    { 
        Node* root = new Node; //-> YOU should allocate a memory for root.
        root -> data =str[0]; 
        root -> left=nullptr;  // use nullptr instead of NULL for c++11 or later.
        root -> right=nullptr; 
        
        return root; // exit needed!
    }
    
    Node* root = new Node;
    root->left = nullptr;
    root->right = nullptr;
    root->data = 0;
    

    //// to store the data of root
    //2. THERE NEED take an integer until first '(' symbol.
    {
        std::size_t i = 0;
        while (i < str.size() && str[i] != '(' )
           ++i;
        // str[0 .. i)  - interval is an integer.
        int val = 0;
        (void)std::from_chars(str.data(), str.data() + i, val); // FOR simplifity don't check validness of conversation.
        str.remove_prefix(i);
        
        root->data = val;
    }

    //3. SKIP balanced '(' and ')' 
    /*stack < char > st;
    for (j = i; j < J; j++) {
        if (str[j] == '(') st.push(str[j]);
        else if (str[j] == ')') st.pop();
        if (st.empty()) break;
    }
    * */
    /** we can implement it another way */
    assert(!str.empty() && str[0] == '(' );
    std::string_view within_bracket;
    {
        int balanced_brackets = 0;
        std::size_t i = 0;
        while (i < str.size())
        {
            if (str[i] == '(') ++ balanced_brackets;
            else if (str[i] == ')' ) --balanced_brackets;
            i++;
            if (balanced_brackets == 0)
              break;
        }
        assert (i > 0 && str[ i - 1 ] == ')' );
        //           0  1 2 3   
        // str[0..i) - is  '(' ... ')'  symbols.
        within_bracket = std::string_view(str.data() + 1, i - 2);
        str.remove_prefix(i);
    }
    
    /****4. THIS second balanced bracket check */
    std::string_view second_within_bracket;
    /*
    for (l = j + 1; l < J; l++) {
        if (str[l] == '(') st.push(str[l]);
        else if (str[l] == ')') st.pop();
        if (st.empty()) break;
    }
    k = j + 1;
    */
    assert(!str.empty() && str[0] == '(' );
    // ========== second balanced brackets check ==========
    {
        std::size_t i = 0;
        int balanced_brackets = 0;
        while (i < str.size())
        {
            if (str[i] == '(') ++ balanced_brackets;
            else if (str[i] == ')' ) --balanced_brackets;
            i++;
            if (balanced_brackets == 0)
              break;
        }
        //           0  1 2 3   
        // str[0..i) - is  '(' ... ')'  symbols.
        second_within_bracket = std::string_view(str.data() + 1, i - 2);
        str.remove_prefix(i);
        
    }
    //================================
    
    /*
    if (j - i == 2) root -> left -> data = str[i + 1];
  else
    root -> left =  create(i + 1, j - 1, str);
    if (l == k) root -> right=NULL;
  else if (l - k == 2) root -> right -> data = str[k + 1];
  else
    root -> right =  create(root -> right, k + 1, l - 1, str);
    */
    root->left = create(within_bracket);
    root->right = create(second_within_bracket);
    
    return root;
}
Node * treeFromString(std::string_view str){
    Node * p = create(str);
    return p;

}

void printTree(Node* root, int level = 0)
{
    if (root==nullptr) return;
    for (int i= 0; i < level; ++i) std::cout << "--";
    std::cout << " data = " << root->data << std::endl;
    printTree(root->left, level + 1);
    printTree(root->right, level + 1);
}

int main(){
    
    std::string str = "12(8(7)(5))(9(3)(2(1)(8)))";
    Node * expr = treeFromString(str);
    printTree(expr);
}

godbold output:

Program returned: 0
 data = 12
-- data = 8
---- data = 55
---- data = 53
-- data = 9
---- data = 51
---- data = 2
------ data = 49
------ data = 56
0

This answer is a bit different, it assumes you are loading a tree of integer values from a string, that could be loaded from a file. Next time you ask a question about code, could you please explain a little bit what the code does? Guessing does take some time and some effort.

I've reused the main() and PrintTree() functions from Khurshid Normuradov's answer. I hope he won't mind.

I took the liberty to add modern c++ coding techniques because this question is tagged c++17, so you're getting an example in c++17.

#include <algorithm>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>

struct Node {
    std::unique_ptr<Node> left = nullptr;
    std::unique_ptr<Node> right = nullptr;
    int value = 0;
};

std::unique_ptr<Node> treeFromString(std::string_view str) {
    std::cout << "treeFromString(\"" << str << "\")\n";

    if (str.empty()) return {};

    auto node = std::make_unique<Node>();

    //  extract an int
    auto pos = str.find_first_not_of("0123456789");
    auto val = str.substr(0, pos);

    // optional: std::stoi() would throw anyway in this case
    if (val.empty())
        throw std::runtime_error("invalid value in expression");

    node->value = std::stoi(std::string{val});

    if (val.length() == str.length()) return node;

    str = str.substr(val.length());

    // Both left/right parsing are similar and use this 
    // common subroutine.
    // expects parens delimited string as input.
    // param  str   in: str string to parse from
    //              out: whatever's left to parse
    // returns  string content within parens, parens not included.
    auto extract_parens_contents = [](std::string_view& str) {
        
        // right here would be the perfect place to insert code to skip 
        // whitespace if you ever needed to do that.

        // find parens extent       
        int parens = 0;
        auto parens_end =
            std::find_if(str.begin(), str.end(), [&parens](char c) {
                parens += (c == '(') - (c == ')');
                return (parens == 0);
            });

        if (parens_end == str.end())
            throw std::runtime_error("unbalanced parens in expression");

        // extract result
        auto result = std::string_view(
            str.begin() + 1, std::distance(str.begin() + 1, parens_end));

        // remove spent bytes from input stream
        str = std::string_view(
            parens_end + 1,
            str.length() - std::distance(str.begin(), parens_end + 1));

        return result;
    };

    node->left = treeFromString(extract_parens_contents(str));
    node->right = treeFromString(extract_parens_contents(str));

    return node;
}

// special thanks to user Khurshid Normuradov, who originally wrote the two functions below.
// it would be difficult to writing something that would be any better for the 
// intended purpose.

void printTree(Node* root, int level = 0) {
    if (root == nullptr) return;
    for (int i = 0; i < level; ++i) std::cout << "--";
    std::cout << " data = " << root->value << std::endl;
    printTree(root->left.get(), level + 1);
    printTree(root->right.get(), level + 1);
}

int main() {
    std::string str = "12(8(7)(5))(9(3)(2(1)(8)))";
    auto expr = treeFromString(str);
    printTree(expr.get());
}

You can play with the code here: https://godbolt.org/z/ch3zv5KTT

Michaël Roy
  • 6,338
  • 1
  • 15
  • 19