Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save KnightChaser/24af1305e9c0909280beec58e1051845 to your computer and use it in GitHub Desktop.
Save KnightChaser/24af1305e9c0909280beec58e1051845 to your computer and use it in GitHub Desktop.
A C++ implementation for calculation with reverse polish notation(postfix notation).
#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