支持負號,小數
負號只能出現在表達式開始和緊貼着括號
大部分的思路都是維護一個棧,讓優先級單調遞減
表達式中,*,/> +,- > (,) > #,同級的話左邊的大於右邊
目錄
聲明
#pragma once
#include<string>
#include<stack>
using namespace std;
class Expressions {
private:
static int level(const char&);
static int cmp(const char&, const char&);
static bool is_operator(const char&);
static double calculate(const double& left_operand, const double& right_operand, const char& op);
public:
static double infix_expression(const string&);
static string expression_to_rpn(const string&);
static double evaluate_rpn(const string&);
static string expression_to_pn(const string&);
static double evaluate_pn(const string&);
};
輔助函數
/**
* 獲得操作符級別
* @param op 操作符
* @return 操作符級別
*/
int Expressions::level(const char &op) {
if (op == '#') {
return 0;
}
else if (op == '(' || op == ')') {
return 1;
}
else if (op == '+' || op == '-') {
return 2;
}
return 3;
}
/**
* 右邊的操作符與左邊的操作符對比
* @param left_operator 表達式左邊的操作符
* @param right_operator 表達式右邊的操作符
* @return 大於返回1,等於返回0,小於返回-1
*/
int Expressions::cmp(const char &left_operator, const char &right_operator) {
//括號同級
if (left_operator == '(' && right_operator == ')') {
return 0;
}
else if (right_operator == '(') {
//右邊的括號一定是要先算的
return 1;
}
if (level(left_operator) < level(right_operator)) {
return 1;
}
//相同的操作符左邊的優先級更高
return -1;
}
/**
* 是否是操作符
* @param op 字符
* @return 是否是操作符
*/
bool Expressions::is_operator(const char &op) {
return op == '+' || op == '-' || op == '*' || op == '/' || op == '(' || op == ')';
}
/**
* 計算
* @param left_operand 左操作數
* @param right_operand 右操作數
* @param op 操作符
* @return 計算結果
*/
double Expressions::calculate(const double &left_operand, const double &right_operand, const char &op) {
if (op == '+') {
return left_operand + right_operand;
}
else if (op == '-') {
return left_operand - right_operand;
}
else if (op == '*') {
return left_operand * right_operand;
}
return left_operand / right_operand;
}
中綴表達式求值
/**
* 計算中綴表達式
* @param expression 中綴表達式
* @return 計算結果
*/
double Expressions::infix_expression(const string &expression) {
//操作數棧
stack<double> operands;
//符號棧
stack<char> operators;
//表達式開始
operators.push('#');
//是否是負數
bool isNegative = false;
//是否讀到第一個
bool first = true;
//左邊是否是左括號
bool pre_left_parenthesis = false;
size_t i = 0;
while (i < expression.size()) {
//去除多餘空格
while (i < expression.size() && expression[i] == ' ') {
++i;
}
//結束
if (i == expression.size()) {
break;
}
//表達式第一個是負號
if (expression[i] == '-' && first) {
first = false;
isNegative = true;
++i;
continue;
}
first = false;
char right_op = expression[i];
if (is_operator(right_op)) {
//-緊貼着左括號的話是負號
if (right_op == '-' && pre_left_parenthesis) {
isNegative = true;
pre_left_parenthesis = false;
++i;
continue;
}
pre_left_parenthesis = false;
char left_op = operators.top();
int cmp_result = cmp(left_op, right_op);
//棧頂的操作符大於等於當前的操作符
while (cmp_result != 1) {
//左括號碰到了右括號
if (cmp_result == 0) {
operators.pop();
break;
}
else {
double right_num = operands.top();
operands.pop();
double left_num = operands.top();
operands.pop();
operands.push(calculate(left_num, right_num, left_op));
operators.pop();
left_op = operators.top();
cmp_result = cmp(left_op, right_op);
}
}
if (right_op != ')') {
operators.push(right_op);
if (right_op == '(') {
pre_left_parenthesis = true;
}
}
++i;
}
else {
pre_left_parenthesis = false;
size_t j = i + 1;
while ((j < expression.size() && ('0' <= expression[j] && expression[j] <= '9')) || expression[j] == '.') {
++j;
}
//操作數
double temp = stod(expression.substr(i, j - i));
//負數
if (isNegative) {
temp = -temp;
isNegative = false;
}
operands.push(temp);
i = j;
}
}
char op = operators.top();
//處理剩下的操作符
while (op != '#') {
double right_num = operands.top();
operands.pop();
double left_num = operands.top();
operands.pop();
operands.push(calculate(left_num, right_num, op));
operators.pop();
op = operators.top();
}
return operands.top();
}
中綴表達式轉後綴表達式
/**
* 中綴表達式轉後綴表達式(逆波蘭式)
* @param expression 中綴表達式
* @return 後綴表達式
*/
string Expressions::expression_to_rpn(const string &expression) {
//後綴表達式
string ans;
//符號棧
stack<char> operators;
//是否是負數
bool isNegative = false;
//是否讀到第一個
bool first = true;
//左邊是否是左括號
bool pre_left_parenthesis = false;
size_t i = 0;
operators.push('#');
while (i < expression.size()) {
//去掉多餘的空格
while (i < expression.size() && expression[i] == ' ') {
++i;
}
//結束
if (i == expression.size()) {
break;
}
//表達式第一個是負號
if (expression[i] == '-' && first) {
first = false;
isNegative = true;
++i;
continue;
}
first = false;
char right_op = expression[i];
if (is_operator(right_op)) {
//-緊貼着左括號的話是負號
if (right_op == '-' && pre_left_parenthesis) {
isNegative = true;
pre_left_parenthesis = false;
++i;
continue;
}
pre_left_parenthesis = false;
char left_op = operators.top();
int cmp_result = cmp(left_op, right_op);
//棧頂的操作符大於等於當前的操作符
while (cmp_result != 1) {
operators.pop();
//左括號碰到了右括號
if (cmp_result == 0) {
break;
}
else {
ans.push_back(' ');
ans.push_back(left_op);
left_op = operators.top();
cmp_result = cmp(left_op, right_op);
}
}
if (right_op != ')') {
operators.push(right_op);
if (right_op == '(') {
pre_left_parenthesis = true;
}
}
++i;
}
else {
pre_left_parenthesis = false;
size_t j = i + 1;
while ((j < expression.size() && ('0' <= expression[j] && expression[j] <= '9')) || expression[j] == '.') {
++j;
}
//操作數
double temp = stod(expression.substr(i, j - i));
//負數
if (isNegative) {
temp = -temp;
isNegative = false;
}
ans += " ";
ans += to_string(temp);
i = j;
}
}
char op = operators.top();
//處理剩下的操作符
while (op != '#') {
ans.push_back(' ');
ans.push_back(op);
operators.pop();
op = operators.top();
}
i = 0;
//去掉前導空格
while (i < ans.size() && ans[i] == ' ') {
++i;
}
return ans.substr(i);
}
計算後綴表達式
/**
* 計算後綴表達式(逆波蘭式)
* @param expression 後綴表達式
* @return 計算結果
*/
double Expressions::evaluate_rpn(const string &expression) {
//操作數
stack<double> operands;
size_t i = 0;
while (i < expression.size()) {
//去除多餘空格
while (i < expression.size() && expression[i] == ' ') {
++i;
}
//結束
if (i == expression.size()) {
break;
}
//數字(包括負數)
if ((expression[i] == '-' && i < expression.size() - 1 &&
'0' <= expression[i + 1] && expression[i + 1] <= '9') ||
('0' <= expression[i] && expression[i] <= '9')) {
size_t j = i + 1;
while ((j < expression.size() && ('0' <= expression[j] && expression[j] <= '9')) || expression[j] == '.') {
++j;
}
double temp = stod(expression.substr(i, j - i));
operands.push(temp);
i = j;
}
else if (is_operator(expression[i])) {
//計算
double right_num = operands.top();
operands.pop();
double left_num = operands.top();
operands.pop();
operands.push(calculate(left_num, right_num, expression[i]));
++i;
}
}
return operands.top();
}
中綴表達式轉前綴表達式
/**
* 中綴表達式轉前綴表達式
* @param expression 中綴表達式
* @return 前綴表達式
*/
string Expressions::expression_to_pn(const string &expression) {
stack<string> result;
stack<char> operators;
operators.push('#');
bool pre_minus = false;
int i = static_cast<int>(expression.size() - 1);
//左邊的操作數與右邊的操作符對比
auto temp_cmp = [](const char& left_operator, const char& right_operator) {
//左邊的操作數的右括號要先算
if (left_operator == ')'){
return 1;
}
else if (left_operator == '(' && right_operator == ')'){
return 0;
}
//相同的左邊的優先級高
if (level(left_operator) >= level(right_operator)){
return 1;
}
return -1;
};
//從右邊往左邊掃描
while (i >= 0) {
//去掉多餘的空格
while (i >= 0 && expression[i] == ' ') {
--i;
}
//結束
if (i < 0) {
break;
}
char left_op = expression[i];
if (is_operator(left_op)) {
if (left_op == '-') {
int j = i - 1;
while (j >= 0 && expression[j] == ' ') {
--j;
}
//表達式第一個是符號
if (j < 0) {
pre_minus = true;
break;
}
}
char right_op = operators.top();
int cmp_result = temp_cmp(left_op, right_op);
//棧頂的操作符大於等於當前的操作符
while (cmp_result != 1) {
//左括號遇到右括號
if (cmp_result == 0) {
operators.pop();
break;
}
else {
result.push(string(1, right_op));
operators.pop();
right_op = operators.top();
cmp_result = temp_cmp(left_op, right_op);
}
}
if (left_op != '(') {
operators.push(left_op);
pre_minus = false;
if (left_op == '-') {
pre_minus = true;
}
}
else if (pre_minus) {
//左括號緊貼着的是符號,所以把棧頂的操作數變成負的
string t = result.top();
result.pop();
result.push("-" + t);
pre_minus = false;
}
--i;
}
else {
pre_minus = false;
int j = i - 1;
while (j >= 0 && (('0' <= expression[j] && expression[j] <= '9') || expression[j] == '.')) {
--j;
}
result.push(expression.substr(j + 1, i - j));
i = j;
}
}
//表達式第一個是符號
if (pre_minus) {
operators.pop();
string t = result.top();
result.pop();
result.push("-" + t);
}
char op = operators.top();
//處理剩下的操作符
while (op != '#') {
result.push(string(1, op));
operators.pop();
op = operators.top();
}
string ans = result.top();
result.pop();
//逆序
while (!result.empty()) {
ans += " ";
ans += result.top();
result.pop();
}
return ans;
}
計算前綴表達式
/**
* 計算前綴表達式(波蘭式)
* @param expression 前綴表達式
* @return 計算結果
*/
double Expressions::evaluate_pn(const string &expression) {
//操作數棧
stack<double> operands;
int i = static_cast<int>(expression.size() - 1);
//從右往左掃描
while (i >= 0) {
//去掉多餘空格
while (i >= 0 && expression[i] == ' ') {
--i;
}
//結束
if (i < 0) {
break;
}
//操作數(包括負數)
if ('0' <= expression[i] && expression[i] <= '9') {
int j = i - 1;
while (j >= 0 && (
('0' <= expression[j] && expression[j] <= '9')
|| expression[j] == '.'
|| expression[j] == '-')) {
--j;
}
double temp = stod(expression.substr(j + 1, i - j));
operands.push(temp);
i = j;
}
else if (is_operator(expression[i])) {
double left_num = operands.top();
operands.pop();
double right_num = operands.top();
operands.pop();
operands.push(calculate(left_num, right_num, expression[i]));
--i;
}
}
return operands.top();
}