字串表示式求值(支援多種型別運算子)
阿新 • • 發佈:2020-07-14
一、說明
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 charprev = 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; }
上述程式碼的執行結果為: