Evaluate infix string expression consisting of only addition and multiplication - c++

How can I evaluate an infix string expression which only consists of + and * operators. (No parenthesis).
Example 1:
Input: "1+2*3"
Output: 7
Example 2:
Input: "1+2*3+4"
Output: 11
Here is my code I have so far (which is not giving correct result), I wonder if I can do it with one stack (or none)
int evaluateExpression(string s) {
stack<int> operandStack;
stack<char> operatorStack;
string token = "";
for(char &c : s) {
if(c == '*' || c == '+') {
operandStack.push(stoi(token));
operatorStack.push(c);
token = "";
}
else {
token += c;
}
if(operandStack.size() > 1
&& operandStack.size() == operatorStack.size() + 1
&& operatorStack.top() == '*') {
int a = operandStack.top(); operandStack.pop();
int b = operandStack.top(); operandStack.pop();
operandStack.push(a * b);
}
}
while(operandStack.size() > 1) {
int a = operandStack.top(); operandStack.pop();
int b = operandStack.top(); operandStack.pop();
operandStack.push(a + b);
}
return operandStack.top();
}
Note: do not want to use any non-standard libraries. Ideally with no use of any library.

Yes, you do need only one stack. You can use the standard approach with a shift-reduce parser. In your case, and the simple grammar, this may be already a little bit too much. But I will describe it anyway.
The secret is to use a "parse stack". So only one stack. Not an operator and operand stack. There you will use attributed tokens. A token has a type, like ADD, MULT, NUMBER and, an associated attribute. The attribute is usually a union or a struct. It would be empty for ADD and MULT and would contain a value for NUMBER.
The scanner, which has usually the function getNextToken will produce your tokens. In your case, extremely simple, just those 3 tokens.
Then, in a loop, you will do always the following actions.
Always push the fresh token onto the parse stack
Try to match the top of the stack with a production of the grammar (and look ahead token)
Reduce the stack (Remove matched elements), evaluate the expression, and put the result on the parse stack
So, always: Shift, Match, Reduce
In your case you need for the match function one lookahead symbol, so, the next token. You will find exactly such an example here. There you can find a compiler, with one front end (Scanner, Parser) and 2 different code generators as back end. The code generators are not needed for you task, you can directly evaluate while reducing.
But, for such an easy grammar, you do not need a stack at all. In the book crafting A Compiler with C is a good example. My copy of the book is from 1991, but of course the content is still valid.
They basically write a function for each production/terminal/non-terminal in the grammar and evaluate the tokens and call the functions of other terminals or non-terminals. Interesting approach and not difficult for your use case.
Hope this helps a little . . .

int evaluateExpression(string s) {
string token = "";
char currOperator = '+';
stack<int> st;
string temp = s + '.';
for(const char &c : temp) {
if(isdigit(c)) {
token += c;
}
else if(c != ' ') {
if(currOperator == '*') {
int stackTop = st.top();
st.pop();
st.push(stackTop * stoi(token));
}
else if(currOperator == '+') {
st.push(stoi(token));
}
token = "";
currOperator = c;
}
}
int result = 0;
while(!st.empty()) {
result += st.top();
st.pop();
}
return result;
}

Related

makeValidWord(std::string word) not working properly

I'm programming a hash table thing in C++, but this specific piece of code will not run properly. It should return a string of alpha characters and ' and -, but I get cases like "t" instead of "art" when I try to input "'aRT-*".
isWordChar() return a bool value depending on whether the input is a valid word character or not using isAlpha()
// Words cannot contain any digits, or special characters EXCEPT for
// hyphens (-) and apostrophes (') that occur in the middle of a
// valid word (the first and last characters of a word must be an alpha
// character). All upper case characters in the word should be convertd
// to lower case.
// For example, "can't" and "good-hearted" are considered valid words.
// "12mOnkEYs-$" will be converted to "monkeys".
// "Pa55ive" will be stripped "paive".
std::string WordCount::makeValidWord(std::string word) {
if (word.size() == 0) {
return word;
}
string r = "";
string in = "";
size_t incr = 0;
size_t decr = word.size() - 1;
while (incr < word.size() && !isWordChar(word.at(incr))) {
incr++;
}
while (0 < decr && !isWordChar(word.at(decr))) {
decr--;
}
if (incr > decr) {
return r;
}
while (incr <= decr) {
if (isWordChar(word.at(incr)) || word.at(incr) == '-' || word.at(incr) == '\'') {
in =+ word.at(incr);
}
incr++;
}
for (size_t i = 0; i < in.size(); i++) {
r += tolower(in.at(i));
}
return r;
}
Assuming you can use standard algorithms its better to rewrite your function using them. This achieves 2 goals:
code is more readable, since using algorithms shows intent along with code itself
there is less chance to make error
So it should be something like this:
std::string WordCount::makeValidWord(std::string word) {
auto first = std::find_if(word.cbegin(), word.cend(), isWordChar);
auto last = std::find_if(word.crbegin(), word.crend(), isWordChar);
std::string i;
std::copy_if(first, std::next(last), std::back_inserter(i), [](char c) {
return isWordChar(c) || c == '-' || c == '\'';
});
std::string r;
std::transform(i.cbegin(), i.cend(), std::back_inserter(r), std::tolower);
return r;
}
I am going to echo #Someprogrammerdude and say: Learn to use a debugger!
I pasted your code into Visual Studio (changed isWordChar() to isalpha()), and stepped it through with the debugger. Then it was pretty trivial to notice this happening:
First loop of while (incr <= decr) {:
Second loop:
Ooh, look at that; the variable in does not update correctly - instead of collecting a string of the correct characters it only holds the last one. How can that be?
in =+ word.at(incr); Hey, that is not right, that operator should be +=.
Many errors are that easy and effortless to find and correct if you use a debugger. Pick one up today. :)

RPN calculator / post fix calculator

So, i have to make a postfix calculator or a RPN calculator, the question goes like
The task is to write a simplified calculator that works only on integers. Your code has to provide a function called evaluate, which takes one argument: a std::string and returns an integer. The calculator has to work in the following way:
it reads a string character by character,
if it reads a digit it puts it on its own internal stack,
if it reads a space it has to ignore it,
if it reads a character +,-, * or / it performs the operation on two topmost elements of the stack, deletes them and puts the result on the stack,
when it reaches the end of the std::string argument it returns the top of the stack.
Code:
using namespace std;
int evaluate(string);
bool isdigit(char c);
bool isOp(char c);
bool isdigit(char c)
{
if (c >= '0' && c <= '9')
{
return true;
}
return false;
}
int main()
{
string str;
cout << "\n Enter the input : ";
cin >> str;
evaluate(str);
}
int evaluate(string str)
{
stack<int> mystack;
stack<int> vals;
for (int i = 0; i < str.size(); i++)
{
char c = str[i];
if (isdigit(c))
{
vals.push(c);
}
else if (c == ' ')
{
c = ' ';
cout << str;
}
else
{
int value1, value2, result;
value2 = vals.top();
vals.pop();
value1 = vals.top();
vals.pop();
switch (str[i])
{
case '+':
result = value1 + value2;
mystack.push(result);
break;
case '-':
result = value1 - value2;
mystack.push(result);
break;
case '*':
result = value1 * value2;
mystack.push(result);
break;
case '/':
result = value1 / value2;
mystack.push(result);
break;
}
cout << "result is " << mystack.top();
}
}
}
i expect the actual answers, but i guess the program is not ignoring
the space and when i input the string without spaces theres still a
wrong output
Pay attention that the provided algorithm works only if it gets postfix expression, and not a infix expression.
First problem:
Now, have a look on the following line:
vals.push(c);
c is a char, and vals is an integers stack. When c presenting 1 in your code, the c++ compiler actually see '0' + 1. For example:
For the input 23+, you'll get the result: 101. Why?
'2' != 2 and '3' != 3. Actually the calculation is:
'0' + 2 + '0' + 3, which means 48 + 2 + 48 + 3 because '0' == 48 in ascii code.
To fix this little problem, all you have to do is to decrease the inserted value into the vals stack by '0':
vals.push(c - '0');
Now the result for the input 23+ is: 5.
Second problem:
You are using two stacks instead of one that actually needed. When you push the result value into the second stack (mystack), you actually can't get an access to it (or rather say make it more complicated to use it's value) whenever you will get another part of expression, for example:
23+5*
You can debug this case (use watch table/debug code feature of the IDE you are working with) and see that you are trying to access the 5 of the first result, and get nothing left in the first stack, because the result stored in the second one. Solution: use single stack.
case '+':
result = value1 + value2;
//mystack.push(result);
vals.push(result);
break;
General Improvements
function: isdigit
The first thing I would advice you to do, is to remove the if statement- you don't need it. The following code will do the trick:
bool isdigit(char c) {
return c >= '0' && c <= '9';
}
If this sentence will give you true, the function will return true, otherwise it will return false.
The second thing, is like the comments says, this function already exists in the standard c++ library. Just use:
#include <cctype>
And remove your implementation to this function. The same function with the same name already exists: http://www.cplusplus.com/reference/locale/isdigit/
Important!
This answer was given due to extra time in my life and a boring situation I'm in, but more importantly because I think that it can help to understand how to debug code and to solve future (and more complicated) cases. This kind of questions are Debug questions type. You don't actually have to look here for the answer, but to debug you code and to see what's wrong. Please use the tools you got here wisely, and Good Luck!
EDIT:
For more c++ style solution, in higher difficult level, you can see the following solution (consider it like welcome saying from c++):
int evaluate(string str) {
// [] () -> {} ====> READ ABOUT: Lambda expressions
stack<int> vals;
/*
* pop
* ---
* Returns the top value of a stack, and the pop it from the stack.
*/
auto pop = [] (stack<int> &s) -> int {
int res = s.top();
s.pop();
return res;
};
/*
* op
* --
* Returns a function that execute the selected operator on two integers params.
*/
auto op = [] (char op) -> std::function<int(int, int)> {
switch (op) {
case '+':
default : return [] (int a, int b) -> int { return a + b; };
case '-': return [] (int a, int b) -> int { return a - b; };
case '*': return [] (int a, int b) -> int { return a * b; };
case '/': return [] (int a, int b) -> int { return a / b; };
}
};
/*
* for_each is a loop implementation in c++ as part of the standard library (std).
* It's get the first iterator place (str.begin()), end iterator place (str.end()), and function to execute on
* each value in the collection (between start and end iterators).
*/
std::for_each(str.begin(), str.end(), [&vals, pop, op] (char c) {
if (isdigit(c)) vals.push(c - '0');
else if (c != ' ') vals.push(op(c)(pop(vals), pop(vals)));
// op(c) -> returns a function according to the operator
// op(c)(n1, n2) -> use the returned operator on n1 and n2
// pop(vals) -> function that returns the top value of the stack, and then pop it from the stack.
// op(c)(pop(vals), pop(vals)) -> apply the selected op on the first two values in the stack
});
cout << "The result is: " << vals.top() << endl;
}

Recursion: swapping an e for an a in a string

My problem is that I need to do a recursion for a string and change any e for an a. Every time I enter a word it only prints out the last letter.
My code so far:
string ReplaceEsWithAs(string s)
{
if (s.length() == 1)
{
if (s == "e")
{
s = "a";
return s;
}
else
{
return s;
}
}
else
{
return ReplaceEsWithAs(s.substr(1));
}
}
The only return statements in the function are under the condition
if (s.length() == 1)
It makes sense that the function return always returns a string with one character in it.
In the recursive part, you use:
return ReplaceEsWithAs(s.substr(1));
which calls the function with all but the first character of the string.
If you call with "abcd" from main, you call with "bcd" in the recursive call, then you call with "cd", then you call with "d", which returns "d", which is returned all the way.
You are just discarding the first character in every recursive call.
You need to use:
string ReplaceEsWithAs(string s)
{
if (s.length() == 1)
{
if (s == "e")
{
return "a";
}
// No need for an else
return s;
}
// No need for an else.
return ReplaceEsWithAs(s.substr(0,1)) + ReplaceEsWithAs(s.substr(1));
}
Here is an implementation just by looping through and mutating the string:
string ReplaceEsWithAs(string s) {
for (size_t i = 0; i < s.length(); i++) {
if (s[i] == 'e') {
s[i] = 'a';
}
}
return s;
}
You can access the individual chars in a string by index using []. This code uses a standard for loop to loop through each character. (size_t is an unsigned integer type that is generally used for indices.) For each char s[i], it checks if it's 'e', and if so, sets it to 'a'. Then it just returns the changed string.
This is better than a recursive approach because
it's easier to understand at a glance
it modifies the string in-place, meaning it doesn't have to do needless substring and concatenating (+)
it uses less memory
it won't cause the call stack to overflow for a long input string
Also, the standard library provides a function to do replace operations like this. See this answer.

usage of functions with RPN form

I'm trying to convert mathematical expressions to RPN and then perform symbolic differentiation on them however I'm stuck with some functions like sin() cos() tan()... ln() sqrt() etc. My expression parser only works for more simple cases, like one from the RPN wiki:
3+4*2/(1-5)^2^3
produces the following:
342*15-23^^/+
However when it comes to a more complex formula, like:
sin(2*x^2+6)-(cos(x)/(1-x))
I can't really create the RPN by hand either. My currently working minimalist solution is again implemented according ot the algorithm defined on the Wiki of Shunting-Yard algorithm.
std::string ParseExpression(const std::string &expr) {
std::string ops = "-+/*^";
std::stringstream output;
std::stack<int> stack;
typedef std::string::const_iterator StringIterator;
for (StringIterator TOKEN = expr.cbegin(), END = expr.cend(); TOKEN != END; ++TOKEN) {
const char c = *TOKEN;
size_t idx = ops.find(c);
if (idx != std::string::npos) {
if (stack.empty()) {
stack.push(idx);
}
else {
while (!stack.empty()) {
int prec2 = stack.top() / 2;
int prec1 = idx / 2;
if (prec2 > prec1 || (prec2 == prec1 && c != '^')) {
output << ops[stack.top()];
stack.pop();
}
else {
break;
}
}
stack.push(idx);
}
} else if (c == '(') {
stack.push(-2);
} else if (c == ')') {
while (stack.top() != -2) {
char op = stack.top();
stack.pop();
output << ops[op];
}
stack.pop();
} else {
output << c;
}
}
while (!stack.empty()) {
output << ops[stack.top()];
stack.pop();
}
return output.str();
}
How can I actually include trigonometric and other functions in the RPN formula and process them correctly?
RPN works the same for functions (including trigonometrics) as it does for operators. For trigonometrics, there is only a single argument (unlike operators, which generally have two).
Your example
sin(2*x^2+6)-(cos(x)/(1-x))
would become something like
2x2^*6+_sin_x_cos_1x-/-
I put before-and-after underscores around sin and cos functions for clarity.
Taken a little more abstractly, if you think of operators as two-argument functions and trigonometrics as one-argument functions, it may make a little more sense - the function always comes after its arguments and evaluates the preceding args in stack-popping order (last in, first out). Changing the operators to functions (and appending "b" for binary, "u" for unary) would give us what's below. RPN says that for anything with a "b" (two arguments), the preceding two args are evaluated in the function. For functions ending in "u" (one argument), the preceding argument is evaluated.
2x2_powb__multb_6_plusb__sinu_x_cosu_1x_minusb__divb__minusb_

searching cstring for operators

For an assignment we are given an equation in reverse polish notation. For this example I will use: 2 3 8 * + $ The $ is for denoting the end of the expression. Using a stack, we output the answer.
I have been using:
getline(cin, input, '&');
input.c_str();
to read in the equation and then turn it into a c_string so I can look at the individual elements in the input.
After, I need to check for a few things. If the element is a digit I need to push it onto the stack. If it is white space I need to skip over it.
if (isdigit(input[i]))
{
push();
i++;
}
else if (isspace(input[i]))
{
i++;
}
Now is what has me stuck. If I hit an operator (in this case *) I need to pop the top two elements off the stack and 'operate them' and push the result back to the stack. However, I don't know of anything that would allow me to recognize that they are operators. It is probably a silly question, but help would be greatly appreciated.
You could create a functions map, and match the operators
std::map<char, void (*)(char *)> operators;
operators['*'] = &mult;
operators['+'] = &add;
...
and in your conditionnal statement
if (isdigit(input[i]))
{
push();
i++;
}
else if (isspace(input[i]))
{
i++;
}
else if (operators.find(input[i]) != operators.end())
{
operators[input[i]](input);
}
This way, you will be able to easily add new operators to your calculator.
there are only about 4 or 5 operators. check them with something like:
if (input[i] == '*') {...}
Well, there's no "built-in" way. I would just write an IsOperator(char ch) function. And then do something like:
int IsOperator(char ch)
{
// either add more operators or use a table, etc. here
if (ch == '+' || ch == '-' || ch == '/' || ch == '*')
return 1;
return 0;
}
If you have multi-char operators, like '==', it gets a little more complicated because you have to peek ahead, but the idea is the same.
If you are writing reverse polish notation calculator then on stack you have only numbers, or digits like in your example. BTW don't you accept multi-digits numbers?
Consider two cases, in both you need only std::stack<int> numbers;:
You have digit character c - just put number on stack:
code:
numbers,push(c - '0');
You have operator, let say '+', you replaces top two numbers by their sum:
code:
if (numbers.size() < 2) {
throw std::runtime_error("Too little numbers for +");
}
int a = numbers.top();
numbers.pop();
numbers.top() += a;
You have '$', check if there is only one number on stack, it is the result:
code:
if (numbers.size() != 1) {
throw std::runtime_error("There should be only one!");
}
int result = numbers.top();
numbers.pop();