表达式树

目录

输出中缀表达式

获得表达式树的值

中缀表达式生成表达式树

后缀表达式生成表达式树

前缀表达式生成表达式树

获得后缀表达式

获得前缀表达式


 

#pragma once
#include "TreeNode.h"
#include<stack>
class ExpressionTree {
private:
    TreeNode* root;
    static int level(const char&);
    static int cmp(const char&, const char&);
    static bool is_operator(const char&);
    static void destroy(TreeNode**);
    bool should_print_parenthesis(TreeNode*, bool)const;
    void get_expression(TreeNode*, string&)const;
    double getValue(TreeNode*)const;
public:
    ExpressionTree() :root(nullptr) {};
    void destroy();
    ~ExpressionTree();
    void build_by_infix_expression(const string&);
    void build_by_rpn(const string&);
    void build_by_pn(const string&);
    string get_expression()const;
    string get_rpn()const;
    string get_pn()const;
    double getValue()const;
};

 辅助函数

/**
 * 获得操作符级别
 * @param op 操作符
 * @return 操作符级别
 */
int ExpressionTree::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 ExpressionTree::cmp(const char &left_operator, const char &right_operator) {
    if (left_operator == '(' && right_operator == ')') {
        return 0;
    }
    else if (right_operator == '(') {
        return 1;
    }
    int op1_level = level(left_operator);
    int op2_level = level(right_operator);
    if (op1_level < op2_level) {
        return 1;
    }
    return -1;
}
/**
 * 是否是操作符
 * @param op 字符
 * @return 是否是操作符
 */
bool ExpressionTree::is_operator(const char &op) {
    return op == '+' || op == '-' || op == '*' || op == '/' || op == '(' || op == ')';
}
/**
 * 销毁二叉树
 * @param rt 当前节点的地址
 */
void ExpressionTree::destroy(TreeNode **rt) {
    if ((*rt)->left != nullptr) {
        destroy(&((*rt)->left));
    }
    if ((*rt)->right != nullptr) {
        destroy(&((*rt)->right));
    }
    delete (*rt);
    *rt = nullptr;
}

输出中缀表达式

主要是中序遍历

关于括号

1、如果根节点是+号,那么无论左子树以及右子树是什么操作符,它们都是不需要加括号的,因为根节点+号是最小优先级的

2、如果根节点是-号,那么只有右子树是+号或者-号时,右子树才需要加括号(减号不满足结合律)

3、如果根节点是*号,那么只有左子树或右子树是+号或者-号时,它们才需要加括号

4、如果根节点是/号,那么如果左子树或右子树是+号或者-号时,它们需要加括号,其次,如果右子树是*号或者/号时,右子树也需要加括号(除号不满足结合律)

/**
 * 在输出中缀表达式时是否应该添加括号
 * @param rt 根
 * @param isLeft 左子树还是右子树
 * @return 是否应该添加括号
 */
bool ExpressionTree::should_print_parenthesis(TreeNode *rt, bool isLeft) const {
    if (rt == nullptr) {
        return false;
    }
    TreeNode* left = rt->left;
    TreeNode* right = rt->right;
    //叶子节点
    if (left == nullptr || right == nullptr) {
        return false;
    }
    string root_data = rt->data;
    string left_data = left->data;
    string right_data = right->data;
    //左子树
    if (isLeft) {
        //根是*,/时,如果左子树是+或者-,则他们优先级更高,应该先算,所以要加括号
        if (root_data == "*" || root_data == "/") {
            if (left_data == "+" || left_data == "-") {
                return true;
            }
        }
    }
    else {
        //根是-,*,/时,如果右子树是+或者-,则他们优先级更高,应该先算,所以要加括号
        if (root_data == "-" || root_data == "*" || root_data == "/") {
            if (right_data == "+" || right_data == "-") {
                return true;
            }//根是/时,如果右子树是*或者/,由于不满足结合律,所以要加括号
            else if (root_data == "/" && (right_data == "*" || right_data == "/")) {
                return true;
            }
        }
    }
    return false;
}
/**
 * 获得中缀表达式
 * @param rt 根
 * @param result 中缀表达式
 */
void ExpressionTree::get_expression(TreeNode *rt, string &result) const {
    if (rt == nullptr) {
        return;
    }
    //中序遍历

    if (rt->left != nullptr) {
        if (should_print_parenthesis(rt, true)) {
            result += "(";
            get_expression(rt->left, result);
            result += ")";
        }
        else {
            get_expression(rt->left, result);
        }
    }
    result += rt->data;
    if (rt->right != nullptr) {
        if (should_print_parenthesis(rt, false)) {
            result += "(";
            get_expression(rt->right, result);
            result += ")";
        }
        else {
            get_expression(rt->right, result);
        }
    }
}

获得表达式树的值

/**
 * 求表达式树的值
 * @param rt 根
 * @return 结果
 */
double ExpressionTree::getValue(TreeNode *rt) const {
    if (rt == nullptr) {
        return 0;
    }
    double left = getValue(rt->left);
    double right = getValue(rt->right);
    string op = rt->data;
    if (op == "+") {
        return left + right;
    }
    else if (op == "-") {
        return left - right;
    }
    else if (op == "*") {
        return left * right;
    }
    else if (op == "/") {
        return left / right;
    }
    return stod(rt->data);
}
/**
 * 求表达式树的值
 * @return 结果
 */
double ExpressionTree::getValue() const {
    return getValue(this->root);
}

中缀表达式生成表达式树

基本和中缀表达式求值一样

/**
 * 中缀表达式生成表达式树
 * @param expression 中缀表达式
 */
void ExpressionTree::build_by_infix_expression(const string &expression) {
    stack<TreeNode*> tree_stack;
    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 {
                    TreeNode* right = tree_stack.top();
                    tree_stack.pop();
                    TreeNode* left = tree_stack.top();
                    tree_stack.pop();
                    tree_stack.push(new TreeNode(left, right, 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;
            //操作数
            while ((j < expression.size() && ('0' <= expression[j] && expression[j] <= '9')) || expression[j] == '.') {
                ++j;
            }
            string temp = expression.substr(i, j - i);
            if (isNegative) {
                temp.insert(0,"-");
                isNegative = false;
            }
            tree_stack.push(new TreeNode(temp));
            i = j;
        }
    }
    char op = operators.top();
    //处理剩下的操作符
    while (op != '#') {
        TreeNode* right = tree_stack.top();
        tree_stack.pop();
        TreeNode* left = tree_stack.top();
        tree_stack.pop();
        tree_stack.push(new TreeNode(left, right, op));
        operators.pop();
        op = operators.top();
    }
    destroy();
    this->root = tree_stack.top();
}

后缀表达式生成表达式树

基本和后缀表达式求值一样

/**
 * 后缀表达式生成表达式树
 * @param expression 后缀表达式
 */
void ExpressionTree::build_by_rpn(const string &expression) {
//操作数
    stack<TreeNode*> tree_stack;
    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;
            }
            tree_stack.push(new TreeNode(expression.substr(i, j - i)));
            i = j;
        }
        else if (is_operator(expression[i])) {
            TreeNode* right = tree_stack.top();
            tree_stack.pop();
            TreeNode* left = tree_stack.top();
            tree_stack.pop();

            tree_stack.push(new TreeNode(left, right, expression[i]));
            ++i;
        }

    }
    destroy();
    this->root = tree_stack.top();
}

前缀表达式生成表达式树

基本和前缀表达式求值一样

/**
 * 前缀表达式生成表达式树
 * @param expression 前缀表达式
 */
void ExpressionTree::build_by_pn(const string &expression) {
    stack<TreeNode*> tree_stack;
    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;
            }
            tree_stack.push(new TreeNode(expression.substr(j + 1, i - j)));
            i = j;
        }
        else if (is_operator(expression[i])) {
            TreeNode* left = tree_stack.top();
            tree_stack.pop();
            TreeNode* right = tree_stack.top();
            tree_stack.pop();

            tree_stack.push(new TreeNode(left, right, expression[i]));
            --i;
        }
    }
    destroy();
    this->root = tree_stack.top();
}

获得后缀表达式

后序遍历

/**
 * 获得后缀表达式
 * @return 后缀表达式
 */
string ExpressionTree::get_rpn() const {
    string result;
    bool first = true;
    stack<TreeNode*> s;
    TreeNode* p = this->root, * pre = nullptr;
    while (p != nullptr || !s.empty()) {
        //压入当前节点
        while (p != nullptr) {
            s.push(p);
            p = p->left;
        }
        p = s.top();
        //如果没有右子树或者右子树已经访问过了,那么就可以访问根节点
        if (p->right == nullptr || p->right == pre) {
            if (!first) {
                result += " ";
            }
            first = false;
            result += p->data;
            pre = p;
            s.pop();
            p = nullptr;
        }
        else {
            //访问右子树
            p = p->right;
        }
    }
    return result;
}

获得前缀表达式

前序遍历

/**
 * 获得前缀表达式
 * @return 前缀表达式
 */
string ExpressionTree::get_pn() const {
    stack<TreeNode*> s;
    TreeNode* p = this->root;
    string result;
    bool first = true;
    while (p != nullptr || !s.empty()) {
        //一直向左子树访问
        while (p) {
            if (!first) {
                result += " ";
            }
            result += p->data;
            first = false;

            if (p->right != nullptr) {
                //存储右子树
                s.push(p->right);
            }
            p = p->left;
        }
        if (!s.empty()) {
            //右子树
            p = s.top();
            s.pop();
        }
    }
    return result;
}

参考资料:

https://juejin.im/post/5c3a2ab06fb9a049dd8084be

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nightmare004

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值