• 字符串表达式求值(支持多种类型运算符)


    一、说明

    1. 输入字符串为中缀表达式,无需转为后缀表达式

    2. 支持的运算符包括:

    算术运算符:"+,-,*,/"

    关系运算符:">,<,>=,<=,=,!="(注意等于运算符采用的是一个等号)

    逻辑运算符:"&&,||"

    3. 支持大于10的数字,不支持负数操作数,但支持中间结果和返回值为负数

    二、算法原理&步骤

    本文算法对中缀表达式形式字符串进行求值,同时支持与或运算和逻辑运算(若含有关系运算符或者逻辑运算符,则输出为1或者0)。类似于加减乘除,将关系运算符和逻辑运算符看作优先级低的运算符进行处理,优先级:算术运算符>关系运算符>逻辑运算符。

    步骤:

    1. 初始化两个空堆栈,一个存放操作数,一个存放运算符。

    2. 从左至右扫描输入字符串,依次读取。

    • 2.1 若为操作数,则压入操作数栈;
    • 2.2 若为运算符,判断其优先级是否大于运算符栈栈顶元素优先级。若大于栈顶元素优先级,则直接压栈;否则,弹出栈顶元素operator,同时依次从操作数栈中弹出两个元素number1,number2,计算表达式(number2 operator number1)的值value,并将值value压入操作数栈。重复上述过程直至当前扫描的操作符优先级大于栈顶元素,然后将当前运算符压栈。

    3. 弹出运算符栈顶元素operator,同时依次从操作数栈中弹出两个元素number1,number2,计算表达式(number2 operator number1)的值value,并将值value压入操作数栈。重复上述过程直至运算符栈为空。

    4. 此时操作数栈应该只有一个元素,即为表达式的值。

    三、代码&测试

    求值函数:

     1 /* 字符串表达式求值
     2  * @param input: 输入的字符串
     3  * @param output: 表达式的值,若含有关系运算符则为1或者0
     4  * return 计算过程是否正常
     5  */
     6 bool ExpValue(string input,int& output)
     7 {
     8     stack<int> operand_stack;
     9     stack<string> operator_stack;
    10 
    11     char prev = 0; // 上一个属于运算符的字符
    12     for (int i = 0; i < input.size(); i++)
    13     {
    14         char c = input[i];
    15         // prev是否是一个完整运算符
    16         if (!isOperator(c) && prev)
    17         {
    18             string new_op = string("").append(1, prev);
    19             addNewOperator(new_op, operand_stack, operator_stack);
    20             prev = 0;
    21         }
    22 
    23         // 数字
    24         if (isdigit(c))
    25         {
    26             int val_c = c - '0';
    27             if (i > 0 && isdigit(input[i - 1]))
    28             {
    29                 int top_num = operand_stack.top();
    30                 top_num = top_num * 10 + val_c;
    31                 operand_stack.pop();
    32                 operand_stack.push(top_num);
    33             }
    34             else
    35                 operand_stack.push(val_c);
    36         }
    37         // 运算符字符
    38         else if (isOperator(c))
    39         {
    40             // 处理两字符运算符
    41             if (prev)
    42             {
    43                 string new_op = string("").append(1, prev).append(1, c);
    44                 addNewOperator(new_op, operand_stack, operator_stack);
    45                 prev = 0;
    46             }
    47             else
    48                 prev = c;
    49         }
    50         else if (c == '(')
    51             operator_stack.push("(");
    52         else if (c == ')')
    53         {
    54             // 处理括号内的运算符
    55             while (operator_stack.top()!="(")
    56             {
    57                 int num1 = operand_stack.top();
    58                 operand_stack.pop();
    59                 int num2 = operand_stack.top();
    60                 operand_stack.pop();
    61                 string op = operator_stack.top();
    62                 operator_stack.pop();
    63 
    64                 int val = Calculate(num2, num1, op);
    65                 operand_stack.push(val);
    66             }
    67             operator_stack.pop(); // 弹出"("
    68         }
    69     }
    70     assert(operand_stack.size() == operator_stack.size() + 1);
    71     // 弹出所有运算符
    72     while(!operator_stack.empty())
    73     {
    74         int num2 = operand_stack.top();
    75         operand_stack.pop();
    76         int num1 = operand_stack.top();
    77         operand_stack.pop();
    78         string op = operator_stack.top();
    79         operator_stack.pop();
    80 
    81         int val = Calculate(num1, num2, op);
    82         operand_stack.push(val);
    83     }
    84 
    85     if (operand_stack.size() == 1) {
    86         output = operand_stack.top();
    87         return true;
    88     }
    89     return false;
    90 }

    其中用到的子函数有:

    /* 判断字符是否属于运算符 */
    bool isOperator(char c)
    {
        switch (c)
        {
        case '-':
        case '+':
        case '*':
        case '/':
        case '%':
        case '<':
        case '>':
        case '=':
        case '!':
        case '&':
        case '|':
            return true;
        default:
            return false;
        }
    }
    
    /* 获取运算符优先级 */
    int getPriority(string op)
    {
        int temp = 0;
        if (op == "*" || op == "/" || op == "%")
            temp = 4;
        else if (op == "+" || op == "-")
            temp = 3;
        else if (op == ">" || op == "<" || op == ">=" || op == "<="
            || op == "=" || op == "!=")
            temp = 2;
        else if (op == "&&" || op == "||")
            temp = 1;
        return temp;
    }
    /* 
     * 返回一个两元中缀表达式的值
     * syntax: num_front op num_back
     * @param num_front: 前操作数
     * @param num_back: 后操作数
     * @param op: 运算符
     */
    int Calculate(int num_front, int num_back, string op)
    {
        if (op == "+")
            return num_front + num_back;
        else if (op == "-")
            return num_front - num_back;
        else if (op == "*")
            return num_front * num_back;
        else if (op == "/")
            return num_front / num_back;
        else if (op == "%")
            return num_front % num_back;
        else if (op == "!=")
            return num_front != num_back;
        else if (op == ">=")
            return num_front >= num_back;
        else if (op == "<=")
            return num_front <= num_back;
        else if (op == "=")
            return num_front == num_back;
        else if (op == ">")
            return num_front > num_back;
        else if (op == "<")
            return num_front < num_back;
        else if (op == "&&")
            return num_front && num_back;
        else if (op == "||")
            return num_front || num_back;
    
        return 0;
    }
    /* 新运算符入栈操作 */
    void addNewOperator(string new_op, stack<int>& operand_stack, stack<string>& operator_stack)
    {
        while (!operator_stack.empty() && getPriority(operator_stack.top()) >= getPriority(new_op))
        {
            int num2 = operand_stack.top();
            operand_stack.pop();
            int num1 = operand_stack.top();
            operand_stack.pop();
            string op = operator_stack.top();
            operator_stack.pop();
    
            int val = Calculate(num1, num2, op);
            operand_stack.push(val);
        }
        operator_stack.push(new_op);
    }
    View Code

    测试结果:

    int main()
    {
        string s0 = "10-1*10+3%2";
        string s1 = "100 + (3-33)*2";
        string s2 = "20+1 >= 20 && 20+1 < 20";
        string s3 = "10>20 || 10/1>=5";
        int ret = -1;
        if (ExpValue(s0, ret))
            cout << s0 << "的值: " << ret << endl;
    
        if (ExpValue(s1, ret))
            cout << s1 << "的值: " << ret << endl;
    
        if (ExpValue(s2, ret))
            cout << s2 << "的值: " << ret << endl;
    
        if (ExpValue(s3, ret))
            cout << s3 << "的值: " << ret << endl;
        return 0;
    }

    上述代码的执行结果为:

  • 相关阅读:
    算法之路 level 01 problem set
    算法原理与实践(链表)
    散列表(HashTable)
    系统设计与实践(实战演练)
    桶排序 + 基数排序
    算法原理与实践(二叉树)
    Total Difference String
    【翻译】std::list::remove
    【翻译】std::remove
    Observer模式实践
  • 原文地址:https://www.cnblogs.com/irvingluo/p/13301157.html
Copyright © 2020-2023  润新知