利用栈表达式求值以及转换

支持负号,小数

负号只能出现在表达式开始和紧贴着括号

大部分的思路都是维护一个栈,让优先级单调递减

表达式中,*,/>  +,-  >  (,)  >  #,同级的话左边的大于右边

目录

声明

辅助函数

中缀表达式求值

中缀表达式转后缀表达式

计算后缀表达式

中缀表达式转前缀表达式 

扫描二维码关注公众号,回复: 9757046 查看本文章

计算前缀表达式 


声明

#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();
}
发布了93 篇原创文章 · 获赞 83 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_39942341/article/details/102513203