Created
May 30, 2023 11:43
-
-
Save KnightChaser/24af1305e9c0909280beec58e1051845 to your computer and use it in GitHub Desktop.
A C++ implementation for calculation with reverse polish notation(postfix notation).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <vector> | |
#include <string> | |
#include <stack> | |
using namespace std; | |
// redefine operator << to print the vector like just strings | |
template <typename S> | |
ostream& operator<<(ostream& os, | |
const vector<S>& vector) | |
{ | |
// Printing all the elements | |
// using << | |
for (auto element : vector) { | |
os << element << " "; | |
} | |
return os; | |
} | |
int operatorPriority(char ch) { | |
if (ch == '+' || ch == '-') return 1; | |
if (ch == '*' || ch == '/') return 2; | |
return 0; | |
} | |
vector<string> transformExpressionRPN(string expression) { | |
// Disassemble each number and operator from the given expression. | |
vector<string> disassembledExpression; | |
string numberStringBuffer; | |
for (char ch : expression) { | |
if (isdigit(ch)) { | |
numberStringBuffer.push_back(ch); | |
} | |
else if (ch == '+' || ch == '-' || ch == '/' || ch == '*' || ch == '(' || ch == ')') { | |
if (!numberStringBuffer.empty()) | |
disassembledExpression.push_back(numberStringBuffer); | |
disassembledExpression.push_back(string(1, ch)); | |
numberStringBuffer = ""; | |
} | |
} | |
// Convert disassembled vector to the reversed polish notation style | |
stack<string> operators; // for operators | |
vector<string> RPNExpression; // the result (RPN-formatted expression) | |
for (string unit : disassembledExpression) { | |
// 1. operands goes straightly | |
if (isdigit(unit[0])) { | |
RPNExpression.push_back(unit); | |
continue; | |
} | |
// 2. Push if the stack is void or unit is "(" | |
else if (operators.empty() || unit == "(") { | |
operators.push(unit); | |
continue; | |
} | |
// 3. If unit is ")", then export the output until "(" | |
else if (unit == ")") { | |
while (operators.top() != "(") { | |
RPNExpression.push_back(operators.top()); | |
operators.pop(); | |
} | |
operators.pop(); // delete "(" itself | |
continue; | |
} | |
// 4. If unit is having a higher priority than the top (two operators conflict), just push | |
else if (operatorPriority(operators.top()[0]) < operatorPriority(unit[0])) { | |
operators.push(unit); | |
continue; | |
} | |
// 5. If unit is having the same or a lower priority than the top (two operators conflict), pop and repeat the process | |
else { | |
while (!operators.empty() && (operatorPriority(operators.top()[0]) >= operatorPriority(unit[0]))) { | |
RPNExpression.push_back(operators.top()); | |
operators.pop(); | |
} | |
operators.push(unit); // then push the current unit | |
} | |
} | |
// If the operators stack is still having some elements, export everything | |
while (!operators.empty()) { | |
RPNExpression.push_back(operators.top()); | |
operators.pop(); | |
} | |
cout << "PNN: " << RPNExpression << endl; | |
return RPNExpression; | |
} | |
double calculateRPNExpression(vector<string> RPNExpression) { | |
stack<double> numbers; | |
for(string unit : RPNExpression) { | |
if (isdigit(unit[0])) { | |
// If unit is a number, put to the number stack | |
numbers.push(stod(unit)); | |
} else { | |
// If unit is an operator, calculate the latest 2 numbers in stack with an operator. | |
double operandB = numbers.top(); numbers.pop(); | |
double operandA = numbers.top(); numbers.pop(); | |
switch(unit[0]) { | |
case '+': | |
numbers.push(operandA + operandB); | |
break; | |
case '-': | |
numbers.push(operandA - operandB); | |
break; | |
case '*': | |
numbers.push(operandA * operandB); | |
break; | |
case '/': | |
numbers.push(operandA / operandB); | |
break; | |
} | |
} | |
} | |
return numbers.top(); | |
} | |
int main() { | |
vector<string> expr = transformExpressionRPN("(27*38*(4/2))-4+(2/8)*447-((28+3)/3-2*5)"); | |
cout << calculateRPNExpression(expr) << endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment