利用棧表達式求值以及轉換

支持負號,小數

負號只能出現在表達式開始和緊貼着括號

大部分的思路都是維護一個棧,讓優先級單調遞減

表達式中,*,/>  +,-  >  (,)  >  #,同級的話左邊的大於右邊

目錄

聲明

輔助函數

中綴表達式求值

中綴表達式轉後綴表達式

計算後綴表達式

中綴表達式轉前綴表達式 

計算前綴表達式 


聲明

#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();
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章