字符串表達式求值(支持多種類型運算符)


一、說明

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;
}

上述代碼的執行結果為:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM