Search code examples
c++stackexpression-treesinfix-notation

Read infix expression into a stack


I've written code to convert an expression tree to preorder and postorder, but I'm struggling to actually build the expression tree from an infix expression. I have a .cc file that will call the build_expression_tree function, call the conversion functions and print out the converted expressions.

This is my current non-working function:

void Expression_Tree::build_expression_tree(char input[], int size)
{
    for (int i = 0; i < size; i++) 
    {
        if (input[i] == ' ')
        {
            i++;
        }
        if(input[i] >= '0' && input[i] <= 9) 
        { 
            ETNode *temp = new ETNode;
            temp->left = temp->right = NULL;
            temp->input = input[i];

            tree_stack.push(temp);
        }
        else if (input[i] == '(') 
        {
            ETNode *temp = new ETNode;
            temp->left = temp->right = NULL;
            temp->input = input[i];

            tree_stack.push(temp);
        }
        else if (input[i] == ')')
        {
            while (tree_stack.top() != '(')
            {
                temp->right = tree_stack.top();
                tree_stack.pop();
                temp->left = tree_stack.top();
                tree_stack.pop();
                tree_stack.pop();
                tree_stack.push(temp);
            }
        }
        else if (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/')
        {
            while (!tree_stack.empty())
            {
                ETNode *temp = new ETNode;
                temp->left = temp->right = NULL;
                temp->input = input[i];

                tree_stack.push(temp);

                temp->right = tree_stack.top();
                tree_stack.pop();
                temp->left = tree_stack.top();
                tree_stack.pop();

                tree_stack.push(temp);
            }
        }
    }
}

The errors I'm getting at this point are: Expression_Tree.h:61:40: error: ISO C++ forbids comparison between pointer and integer

while(tree_stack.top() != '(')

Expression_Tree.h:62:13: error: 'temp' was not declared in this scope

temp->right = tree_stack.top();

Expression_Tree.h:62:13: error: 'temp' was not declared in this scope

temp->left = tree_stack.top();

I know why the last two errors (not declared in scope) are occurring, but I just don't know what to do to fix it whilst making my code work properly.

I don't even know if my code is completely wrong, but any tips would be incredibly appreciated! Thanks.

EDIT: These are the classes that affect the Build_Expression_Tree function.

class ETNode {
public:
    char input;
    ETNode *left, *right;
};

class Expression_Tree { 
public:
    Expression_Tree() { root = 0; };
    ~Expression_Tree() { clear(root); }
    void build_expression_tree(char[], int);
    void inorder() { inorder(root); }
    void preorder() { preorder(root); }
    void postorder() {postorder(root); }
private:
    ETNode* root;
    std::stack<ETNode*> tree_stack;
    void visit(ETNode* p) { std::cout << p->input << " "; } 
    void inorder(ETNode*);
    void preorder(ETNode*);
    void postorder(ETNode*);
    void clear(ETNode*);
};

Solution

  • Here I've split up your example input into a representation of how the stack can be used and the decisions made at each input.

    //    _ = nullptr or empty
    //    # = pointer to subtree (not just a number)
    // | ___ |     |     |     begin (empty element on stack)
    // | 2__ |     |     |  2  make number node and set to top->left if empty, else top->right
    // | 2+_ |     |     |  +  set top->input if not set, else pop parent into left of new node
    // | 2+_ | ___ |     |  (  make new node on stack
    // | 2+_ | 3__ |     |  3  make number node and set to top->left if empty, else top->right
    // | 2+_ | 3*_ |     |  *  set top->input if not set, else pop parent into left of new node
    // | 2+_ | 3*_ | ___ |  (  make new node on stack
    // | 2+_ | 3*_ | 2__ |  2  make number node and set to top->left if empty, else top->right
    // | 2+_ | 3*_ | 2+_ |  +  set top->input if not set, else pop parent into left of new node
    // | 2+_ | 3*_ | 2+2 |  2  make number node and set to top->left if empty, else top->right
    // | 2+_ | 3*# |     |  )  pop it off into its parent
    // | 2+# |     |     |  )  pop it off into its parent
    // | #+_ |     |     |  +  set top->input if not set, else pop parent into left of new node
    // | #+5 |     |     |  5  make number node and set to top->left if empty, else top->right
    

    Note that I have many duplicate statements, one type for ( one for ) one for a number 0-9 and one for each operation +-*/. You already have these divisions in your code so you're on the right track.

    ('s only job should be to create a new node on the top of the stack. In your code, there is no point to set input = '(' because its going to be overwritten by an actual input later and its position in the stack is all that's needed to keep track of it. You should initialize input to '\0' or something else meaning empty.

    )'s job should be to pop the top off the stack and put it where it needs to go. That'll be either the next top's left node if its null, otherwise it'll be top's right node. You don't need to loop down the stack like you do, because it'll always just be the top that we're interested in popping.

    A number's job should be to create itself as a new node and put itself where it needs to go. Just like ) that'll either be the top's left node if its null, otherwise it'll be top's right node. In your code, you make the node but you don't put it anywhere besides on the stack. Its not doing any good there because a number node will always be a leaf node (no right or left).

    Finally an operation's job should be to simply set itself to the top's input. However, there's a special case where the top has already been filled in (when you do 1+2+3 the 1+2 is the node on top). So what you can do in that case is pop off the top, push a new node on top, add the old top as the left, and THEN just set itself to top's input. You don't need a loop.

    After all is done, you can just set root = tree_stack.top().

    If you want the code I can supply it but I hope my explanation is enough.

    Code: This seems to work for me

    void Expression_Tree::build_expression_tree(char input[], int size)
    {
      // assuming empty tree_stack, it shouldn't really be a member 
      // variable since its only used for building
      //std::stack<ETNode*> tree_stack;
    
      // make empty node, should really make a default constructor set all this up
      tree_stack.push(new ETNode);
      tree_stack.top()->left  = nullptr;
      tree_stack.top()->right = nullptr;
      tree_stack.top()->input = '\0';
    
      for (int i = 0; i < size; i++)
      {
        if (input[i] == ' ')
        {
          i++;
        }
        if (input[i] >= '0' && input[i] <= '9') // this 9 had a typo before
        {
          // create number leaf
          ETNode *temp = new ETNode;
          temp->left = nullptr;
          temp->right = nullptr; 
          temp->input = input[i];
    
          // put where it needs to go
          if (tree_stack.top()->left == nullptr)
            tree_stack.top()->left = temp;
          else
            tree_stack.top()->right = temp;
        }
        else if (input[i] == '(')
        {
          // make empty node
          ETNode *temp = new ETNode;
          temp->left = nullptr;
          temp->right = nullptr;
          temp->input = '\0';
    
          tree_stack.push(temp);
        }
        else if (input[i] == ')')
        {
          // pop top from the stack
          ETNode *temp = tree_stack.top();
          tree_stack.pop();
    
          // put where it needs to go
          if (tree_stack.top()->left == nullptr)
            tree_stack.top()->left = temp;
          else
            tree_stack.top()->right = temp;
        }
        else if (input[i] == '+' || input[i] == '-' || input[i] == '*' || input[i] == '/')
        {
          // shuffle node if already filled
          if (tree_stack.top()->input != '\0')
          {
            ETNode *old = tree_stack.top();
            tree_stack.pop();
    
            ETNode *temp = new ETNode;
            temp->left = old;
            temp->right = nullptr;
    
            tree_stack.push(temp);
          }
    
          tree_stack.top()->input = input[i];
        }
      }
    
      // set root node
      root = tree_stack.top();
    }