目錄html
變量定義: str-數學表達式
注:數學表達式的數值支持小數,符號只支持+ - * / ( )這幾種。算法
計算原理::先將數學表達式的字符串(中綴表達式)轉化爲後綴表達式,而後計算後綴表達式的值。
注:爲了運算結果的精度,運算過程當中統一使用decimal類型的數據。ide
例:輸入表達式"10*1.1/(2+8)+1.1+2.2-4.3",輸出結果「0.1」。測試
代碼以下:spa
//測試算法class Program{ static void Main(string[] args) { string str = "10*1.1/(2+8)+1.1+2.2-4.3"; decimal res = Calculator.Calculate(str); Console.WriteLine(str+"="+res); Console.ReadLine(); } }/// <summary>/// 計算數學表達式,基於後綴表達式的實現,可以使用 + - * / ( ) 運算符/// </summary>class Calculator { /// <summary> /// 計算數學表達式的值 /// </summary> /// <param name="str">數學表達式</param> /// <returns></returns> public static decimal Calculate(string str) { try { Queue<string> queue = CreateRPN(str); decimal res = ParseRPN(queue); return res; } catch (OverflowException) { throw new Exception("數據過大致使計算溢出"); } catch (Exception) { throw new Exception("沒法計算錯誤的表達式"); } } //生成後綴表達式 private static Queue<string> CreateRPN(string str) { //臨時存儲+ - * / ( 符號的棧 Stack<char> stack = new Stack<char>(); //存儲後綴表達式的隊列 Queue<string> queue = new Queue<string>(); for (int i = 0; i < str.Length; ) { //若是是空格直接跳過 if (str[i] == ' ') { i++; continue; } else if ((str[i] >= '0' && str[i] <= '9') || (str[i] == '.')) { //當前數 decimal cur = 0; //小數標識 bool isDecimal = false; //小數位數 int num = 0; //特別要注意i < s.length這個條件 while (i < str.Length && ((str[i] >= '0' && str[i] <= '9') || (str[i] == '.'))) { if (str[i] == '.') { isDecimal = true; } else { if (!isDecimal) { cur = cur * 10 + str[i] - '0'; } else { num++; cur = cur + ((decimal)(str[i] - '0')) / (decimal)(Math.Pow(10, num)); } } i++; } queue.Enqueue(cur.ToString()); } else if (str[i] == ')') { //若是是 " )"那麼須要彈出棧中的操做符號,而且把它加入到後綴表達式的隊列中 //一直到遇到符號棧中的 " ( " 爲止 while (stack.Count != 0 && stack.Peek() != '(') { queue.Enqueue(stack.Pop() + ""); } stack.Pop(); i++; } else { //多是 + - * / 這些符號或者是左括號 //這個時候須要判斷符號棧中的棧頂元素與當前遍歷到的字符的優先級的問題 while (stack.Count != 0 && Compare(stack.Peek(), str[i]) < 0) { queue.Enqueue(stack.Pop() + ""); } stack.Push(str[i]); i++; } } while (stack.Count != 0) { queue.Enqueue(stack.Pop() + ""); } return queue; } //處理符號優先級 private static int Compare(char peek, char c) { if (peek == '(' || c == '(') return 1; if (c == '+' || c == '-') return -1; if (c == '*' && (peek == '*' || peek == '/')) return -1; if (c == '/' && (peek == '*' || peek == '/')) return -1; return 1; } //解析後綴表達式 private static decimal ParseRPN(Queue<string> queue) { //結果棧 Stack<decimal> res = new Stack<decimal>(); while (queue.Count != 0) { String t = queue.Dequeue(); if (t.Equals("+") || t.Equals("-") || t.Equals("*") || t.Equals("/")) { decimal a = res.Pop(); decimal b = res.Pop(); decimal result = Calculate(b, a, t); res.Push(result); } else { res.Push(decimal.Parse(t)); } } return res.Pop(); } //基本運算單元 private static decimal Calculate(decimal a, decimal b, String t) { //計算 if (t.Equals("+")) { return a + b; } else if (t.Equals("-")) { return a - b; } else if (t.Equals("*")) { return a * b; } else { return a / b; } }}
注:上面的代碼簡單擴展一下便可支持更復雜的運算符code
中綴表達式轉化爲後綴表達式規則:從左到右遍歷中綴表達式的每一個數字和符號,如果數字就輸出,即成爲後綴表達式的一部分;如果符號,則判斷其與棧頂符號的優先級,是右括號或優先級低於找頂符號(乘除優先加減)則棧頂元素依次出找並輸出,並將當前符號進棧,一直到最終輸出後綴表達式爲止。htm
例:中綴表達式「9+(3-1)3+10/2」轉化爲後綴表達式「9 3 1-3+ 10 2/+」。隊列
後綴表達式的計算過程規則:從左到右遍歷表達式的每一個數字和符號,遇到是數字就進棧,遇到是符號,就將處於棧頂兩個數字出棧,進行運算,運算結果進棧,一直到最終得到結果。ci
堆棧實現計算數學表達式——CSDN
接觸後綴表達式(逆波蘭表示法)——Veda
將中綴表達式轉化爲後綴表達式——Veda
圖解後綴表達式的計算過程——Veda字符串