My lecturer gave me an assignment to create a program to convert and infix expression to postfix using Stacks. I've made the stack classes and some functions to read the infix expression.
But this one function, called convertToPostfix(char * const inFix, char * const postFix)
which is responsible to convert the inFix expression in the array inFix to the post fix expression in the array postFix using stacks, is not doing what it suppose to do. Can you guys help me out and tell me what I'm doing wrong?
The following is code where the functions to convert from inFix to postFix is and convertToPostfix(char * const inFix, char * const postFix)
is what I need help fixing:
void ArithmeticExpression::inputAndConvertToPostfix()
{
char inputChar; //declaring inputChar
int i = 0; //inizalize i to 0
cout << "Enter the Arithmetic Expression(No Spaces): ";
while( ( inputChar = static_cast<char>( cin.get() ) ) != '\n' )
{
if (i >= MAXSIZE) break; //exits program if i is greater than or equal to 100
if(isdigit(inputChar) || isOperator(inputChar))
{
inFix[i] = inputChar; //copies each char to inFix array
cout << inFix[i] << endl;
}
else
cout << "You entered an invalid Arithmetic Expression\n\n" ;
}
// increment i;
i++;
convertToPostfix(inFix, postFix);
}
bool ArithmeticExpression::isOperator(char currentChar)
{
if(currentChar == '+')
return true;
else if(currentChar == '-')
return true;
else if(currentChar == '*')
return true;
else if(currentChar == '/')
return true;
else if(currentChar == '^')
return true;
else if(currentChar == '%')
return true;
else
return false;
}
bool ArithmeticExpression::precedence(char operator1, char operator2)
{
if ( operator1 == '^' )
return true;
else if ( operator2 == '^' )
return false;
else if ( operator1 == '*' || operator1 == '/' )
return true;
else if ( operator1 == '+' || operator1 == '-' )
if ( operator2 == '*' || operator2 == '/' )
return false;
else
return true;
return false;
}
void ArithmeticExpression::convertToPostfix(char * const inFix, char * const postFix)
{
Stack2<char> stack;
const char lp = '(';
stack.push(lp); //Push a left parenthesis ‘(‘ onto the stack.
strcat(inFix,")");//Appends a right parenthesis ‘)’ to the end of infix.
// int i = 0;
int j = 0;
if(!stack.isEmpty())
{
for(int i = 0;i < 100;){
if(isdigit(inFix[i]))
{
postFix[j] = inFix[i];
cout << "This is Post Fix for the first If: " << postFix[j] << endl;
i++;
j++;
}
if(inFix[i] == '(')
{
stack.push(inFix[i]);
cout << "The InFix was a (" << endl;
i++;
//j++;
}
if(isOperator(inFix[i]))
{
char operator1 = inFix[i];
cout << "CUrrent inFix is a operator" << endl;
if(isOperator(stack.getTopPtr()->getData()))
{
cout << "The stack top ptr is a operator1" << endl;
char operator2 = stack.getTopPtr()->getData();
if(precedence(operator1,operator2))
{
//if(isOperator(stack.getTopPtr()->getData())){
cout << "The stack top ptr is a operato2" << endl;
postFix[j] = stack.pop();
cout << "this is post fix " << postFix[j] << endl;
i++;
j++;
// }
}
}
else
stack.push(inFix[i]);
// cout << "Top Ptr is a: "<< stack.getTopPtr()->getData() << endl;
}
for(int r = 0;r != '\0';r++)
cout << postFix[r] << " ";
if(inFix[i] == ')')
{
while(stack.stackTop()!= '(')
{
postFix[j] = stack.pop();
i++;
j++;
}
stack.pop();
}
}
}
}
Note the function convertToPostfix was made using this algorithm:
While the stack is not empty, read infix from left to right and do the following:
If the current character in infix is an operator,
This is basically a comment to the answer from Yuushi.
precedence(rightOp, leftOp)
). Then you should document what the result means - right now you return true if a rOp b lOp c == (a rOp b) lOp c
(yes, the operator order doesn't match what you call - "+" and "-" are not the same in both orders for example).a - b * c
your output is a b c
and the stack is [- *]
. now you read a +
, and you need to pop both operators, resulting in a b c * -
. I.e., the input a - b * c + d
should result in a b c * - d +
Update: appended complete solution (based on Yuushi's answer):
bool isOperator(char currentChar)
{
switch (currentChar) {
case '+':
case '-':
case '*':
case '/':
case '^':
case '%':
return true;
default:
return false;
}
}
// returns whether a `lOp` b `rOp` c == (a `lOp` b) `rOp` c
bool precedence(char leftOperator, char rightOperator)
{
if ( leftOperator == '^' ) {
return true;
} else if ( rightOperator == '^' ) {
return false;
} else if ( leftOperator == '*' || leftOperator == '/' || leftOperator == '%' ) {
return true;
} else if ( rightOperator == '*' || rightOperator == '/' || rightOperator == '%' ) {
return false;
}
return true;
}
#include <stdexcept>
#include <cctype>
#include <sstream>
#include <stack>
std::string convertToPostfix(const std::string& infix)
{
std::stringstream postfix; // Our return string
std::stack<char> stack;
stack.push('('); // Push a left parenthesis ‘(‘ onto the stack.
for(std::size_t i = 0, l = infix.size(); i < l; ++i) {
const char current = infix[i];
if (isspace(current)) {
// ignore
}
// If it's a digit or '.' or a letter ("variables"), add it to the output
else if(isalnum(current) || '.' == current) {
postfix << current;
}
else if('(' == current) {
stack.push(current);
}
else if(isOperator(current)) {
char rightOperator = current;
while(!stack.empty() && isOperator(stack.top()) && precedence(stack.top(), rightOperator)) {
postfix << ' ' << stack.top();
stack.pop();
}
postfix << ' ';
stack.push(rightOperator);
}
// We've hit a right parens
else if(')' == current) {
// While top of stack is not a left parens
while(!stack.empty() && '(' != stack.top()) {
postfix << ' ' << stack.top();
stack.pop();
}
if (stack.empty()) {
throw std::runtime_error("missing left paren");
}
// Discard the left paren
stack.pop();
postfix << ' ';
} else {
throw std::runtime_error("invalid input character");
}
}
// Started with a left paren, now close it:
// While top of stack is not a left paren
while(!stack.empty() && '(' != stack.top()) {
postfix << ' ' << stack.top();
stack.pop();
}
if (stack.empty()) {
throw std::runtime_error("missing left paren");
}
// Discard the left paren
stack.pop();
// all open parens should be closed now -> empty stack
if (!stack.empty()) {
throw std::runtime_error("missing right paren");
}
return postfix.str();
}
#include <iostream>
#include <string>
int main()
{
for (;;) {
if (!std::cout.good()) break;
std::cout << "Enter the Arithmetic Expression: ";
std::string infix;
std::getline(std::cin, infix);
if (infix.empty()) break;
std::cout << "Postfix: '" << convertToPostfix(infix) << "'\n";
}
return 0;
}
So there are a number of problems with your code. I'll post what (should be) a corrected solution, which has copious comments to explain what's happening and where you've made mistakes. A few things up front:
I'll use std::string
instead of char *
because it makes things much cleaner, and honestly, you should be using it in C++
unless you have a very good reason not to (such as interoperability with a C
library). This version also returns a string
instead of taking a char *
as a parameter.
I'm using the stack from the standard library, <stack>
, which is slightly different to your home-rolled one. top()
shows you the next element without removing it from the stack, and pop()
returns void
, but removes the top element from the stack.
It's a free function, not part of a class, but that should be easy to modify - it's simply easier for me to test this way.
I'm not convinced your operator precedence tables are correct, however, I'll let you double check that.
#include <stack>
#include <cctype>
#include <iostream>
std::string convertToPostfix(std::string& infix)
{
std::string postfix; //Our return string
std::stack<char> stack;
stack.push('('); //Push a left parenthesis ‘(‘ onto the stack.
infix.push_back(')');
//We know we need to process every element in the string,
//so let's do that instead of having to worry about
//hardcoded numbers and i, j indecies
for(std::size_t i = 0; i < infix.size(); ++i) {
//If it's a digit, add it to the output
//Also, if it's a space, add it to the output
//this makes it look a bit nicer
if(isdigit(infix[i]) || isspace(infix[i])) {
postfix.push_back(infix[i]);
}
//Already iterating over i, so
//don't need to worry about i++
//Also, these options are all mutually exclusive,
//so they should be else if instead of if.
//(Mutually exclusive in that if something is a digit,
//it can't be a parens or an operator or anything else).
else if(infix[i] == '(') {
stack.push(infix[i]);
}
//This is farily similar to your code, but cleaned up.
//With strings we can simply push_back instead of having
//to worry about incrementing some counter.
else if(isOperator(infix[i]))
{
char operator1 = infix[i];
if(isOperator(stack.top())) {
while(!stack.empty() && precedence(operator1,stack.top())) {
postfix.push_back(stack.top());
stack.pop();
}
}
//This shouldn't be in an else - we always want to push the
//operator onto the stack
stack.push(operator1);
}
//We've hit a right parens - Why you had a for loop
//here originally I don't know
else if(infix[i] == ')') {
//While top of stack is not a right parens
while(stack.top() != '(') {
//Insert into postfix and pop the stack
postfix.push_back(stack.top());
stack.pop();
}
// Discard the left parens - you'd forgotten to do this
stack.pop();
}
}
//Remove any remaining operators from the stack
while(!stack.empty()) {
postfix.push_back(stack.top());
stack.pop();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With