1

I'm trying to evaluate an infix expression in 1 pass without converting it into postfix but it's not giving correct output for some expressions. For eg: 3-5*10/5+10 , (45+5)-5*(100/10)+5

Can someone provide a proper solution to this problem in cpp.

Link to the previous question asked: How to evaluate an infix expression in just one scan using stacks?

Please don't mark it as duplicate as I have tried the algorithm answered in the above given thread but to no avail.

#include<bits/stdc++.h>

int isoperand(char x)
{
    if(x == '+' || x=='-'|| x=='*' || x=='/' || x==')' || x=='(')
        return 0;
    return 1;
}

int Pre(char x)
{
    if(x == '+' || x == '-')
        return 1;
    if(x == '*' || x == '/')
        return 3;
    return 0;
}

int infixevaluation(std::string exp)
{
    std::stack<int> s1; //Operand Stack
    std::stack<char> s2; //Operator Stack
    int i,x,y,z,key;
    i=0;
    while(exp[i]!='\0')
    {

        if(isoperand(exp[i]))
        {
            key = exp[i]-'0';
            s1.push(key);
            i++;
        }
        else if(!isoperand(exp[i]) && s2.empty())
            s2.push(exp[i++]);
        else if(!isoperand(exp[i]) && !s2.empty())
        {
            if(Pre(exp[i])>Pre(s2.top()) && exp[i]!=')')
                s2.push(exp[i++]);
            else if(exp[i]==')' && s2.top() == '(')
            {
                s2.pop();
                i++;
            }
            else if(exp[i]=='(')
                s2.push(exp[i++]);
            else
            {
                x = s1.top();
                s1.pop();
                y = s2.top();
                s2.pop();
                z = s1.top();
                s1.pop();
                if(y == '+')
                    s1.push(z+x);
                else if(y == '-')
                    s1.push(z-x);
                else if(y == '*')
                    s1.push(x*z);
                else if(y == '/')
                    s1.push(z/x);
            } 
        }
    }
    while(!s2.empty())
    {
        x = s1.top();
        s1.pop();
        y = s2.top();
        s2.pop();
        z = s1.top();
        s1.pop();
        if(y == '+')
            s1.push(x+z);
        else if(y == '-')
            s1.push(z-x);
        else if(y == '*')
            s1.push(x*z);
        else if(y == '/')
            s1.push(z/x);
    }
    return s1.top();
}

int main(int argc, char const *argv[])
{
    std::string s;
    getline(std::cin,s);
    std::cout<<infixevaluation(s)<<std::endl;
    return 0;
}
Amey
  • 15
  • 4
  • What is the expected output, and what is the actual output? Also, does [debugging your program](http://ericlippert.com/2014/03/05/how-to-debug-small-programs/) allow you to narrow down where the problem lies? – JaMiT Aug 22 '19 at 02:30
  • It's giving output as floating-point exception for the expression (45+5)-5*(100/10)+5 and for 3-5*10/5+10 output is 1 instead of 3. – Amey Aug 22 '19 at 02:35
  • 1
    An exception is a crash, not output. Your next step should be to [debug your program](http://ericlippert.com/2014/03/05/how-to-debug-small-programs/) to determine where the crash occurs. Then simplify your program (removing functionality) until you have a [mcve] demonstrating the crash. – JaMiT Aug 22 '19 at 02:50
  • 1
    Be careful with `#include` It includes pretty much the entire Standard library, turning your code into something of a minefield . You haven't tacked on `using namespace std;`, which really makes stdc++.h a bad idea by turning your code into a really big minefield, but there are a [whole bunch of other reasons not to use it.](https://stackoverflow.com/questions/31816095/why-should-i-not-include-bits-stdc-h) – user4581301 Aug 22 '19 at 03:53
  • Thanks for asking this question by the way. Including stdc++.h when I took a look at your code found that something corrupted the copy of shared_ptr_base.h in my gcc install. Good to find these things when it's not at a bad time. Think I should consider getting a new hard drive too. Sucker's probably 9 years old. – user4581301 Aug 22 '19 at 04:13
  • 1
    Your code would be a whole lot easier to understand if you used meaningful variable names. For example, `s1` could be `operandStack`. And instead of `x = s1.top()`, how about `operand1 = operandStack.top()`? In a production environment, I wouldn't even check this code for proper operation until it had meaningful variable names. – Jim Mischel Aug 22 '19 at 22:44
  • @user4581301 hahaha... thank you for giving me advice about not including that particular header file. – Amey Aug 22 '19 at 22:50
  • @JimMischel I'll take note of that next time. – Amey Aug 22 '19 at 22:52
  • 'To no avail' is not a problem description. The code in the duplicate is correct. – user207421 Aug 22 '19 at 23:49

1 Answers1

1

Your code can only deal with single-digit operands -- and it has no checks for malformed input, so when you have a multi-digit operand, it runs off the rails.

The easiest fix for the former is just to scan digits when you see a digit -- change the if (isoperand(exp[i]) clause to:

    if (isdigit(exp[i])) {
        int value = 0;
        while (isdigit(exp[i]))
            value = value * 10 + exp[i++] - '0';
        s1.push(value);
    } else ...

For error checking, you should do things like

  • check for spaces and other invalid characters and reject or skip them
  • keep track of whether the last token matched was an operand or an operator, and give errors for two consecutive operands, or two consecutive operators other than ( and )
Chris Dodd
  • 101,438
  • 11
  • 111
  • 197
  • Thank you! It worked. I was using pen and paper to trace the code and I was pushing 2 digit number at once. Should have used a debugger. Silly me! Link to the full solution: http://ideone.com/IV8PAU – Amey Aug 22 '19 at 23:34