標籤:
/// <summary> /// 中綴運算式到逆波蘭運算式的轉換及求值 /// </summary> public class RpnExpression { #region 定義屬性 int Top = -1; #endregion /// <summary> /// 檢查中綴運算式是否合法 /// </summary> /// <param name="exp"></param> /// <returns></returns> public bool IsRight(string exp) { string pMatch = @"\([^\(^\)]+\)";//匹配最“內”層括弧及運算式 string numberMatch = @"\d+(\.\d+)?";//匹配數字 string exMatch = @"^0([-+*/]0)*$";//匹配無括弧的、用0替換所有的數字後的運算式 exp = Regex.Replace(exp, numberMatch, "0");//為簡化檢測,用0替換所有的數字 while (Regex.IsMatch(exp, pMatch)) { foreach (Match match in Regex.Matches(exp, pMatch)) { string tmp = match.Value; tmp = tmp.Substring(1, tmp.Length - 2);//去掉 "("和 ")" if (!Regex.IsMatch(tmp, exMatch)) return false; } exp = Regex.Replace(exp, pMatch, "0");//將最內層的括弧及括弧內運算式直接用一個0代替 } return Regex.IsMatch(exp, exMatch); } #region 產生逆波蘭運算式 /// <summary> /// 擷取逆波蘭運算式 /// </summary> /// <param name="exp"></param> /// <returns></returns> public string RpnExp(string exp) { string S = ""; //尾碼 char[] Operators = new char[exp.Length]; for (int i = 0; i < exp.Length; i++) { char C = exp[i]; switch (C) { case ‘ ‘: //忽略空格 break; case ‘+‘: //操作符 case ‘-‘: while (Top >= 0) //棧不為空白時 { char c = Operators[Top--]; //pop Operator if (c == ‘(‘) { Operators[++Top] = c; //push Operator break; } else { S = S + c; } } Operators[++Top] = C; //push Operator S += " "; break; case ‘*‘: //忽略空格 case ‘/‘: while (Top >= 0) //棧不為空白時 { char c = Operators[Top--]; //pop Operator if (c == ‘(‘) { Operators[++Top] = c; //push Operator break; } else { if (c == ‘+‘ || c == ‘-‘) { Operators[++Top] = c; //push Operator break; } else { S = S + c; } } } Operators[++Top] = C; //push Operator S += " "; break; case ‘(‘: Operators[++Top] = C; S += " "; break; case ‘)‘: while (Top >= 0) //棧不為空白時 { char c = Operators[Top--]; //pop Operator if (c == ‘(‘) { break; } else { S = S + c; } } S += " "; break; default: S = S + C; break; } } while (Top >= 0) { S = S + Operators[Top--]; //pop Operator } return S; } #endregion #region 取逆波蘭運算式的值 /// <summary> /// 擷取逆波蘭運算式的值 /// </summary> /// <param name="rpnExp"></param> /// <returns></returns> public double GetValueByRpn(string rpnExp) { //尾碼運算式計算 double[] Operands = new double[rpnExp.Length]; double x, y, v; Top = -1; string Operand = ""; for (int i = 0; i < rpnExp.Length; i++) { char c = rpnExp[i]; if ((c >= ‘0‘ && c <= ‘9‘) || c == ‘.‘) { Operand += c; } if ((c == ‘ ‘ || i == rpnExp.Length - 1) && Operand != "") //Update { Operands[++Top] = System.Convert.ToDouble(Operand); //push Operands Operand = ""; } if (c == ‘+‘ || c == ‘-‘ || c == ‘*‘ || c == ‘/‘) { if ((Operand != "")) { Operands[++Top] = System.Convert.ToDouble(Operand); //push Operands Operand = ""; } y = Operands[Top--]; //pop 雙目運算子的第二運算元 (後進先出)注意運算元順序對除法的影響 x = Operands[Top--]; //pop 雙目運算子的第一運算元 switch (c) { case ‘+‘: v = x + y; break; case ‘-‘: v = x - y; break; case ‘*‘: v = x * y; break; case ‘/‘: v = x / y; // 第一運算元 / 第二運算元 注意運算元順序對除法的影響 break; default: v = 0; break; } Operands[++Top] = v; //push 中間結果再次入棧 } } v = Operands[Top--]; //pop 最終結果 return v; } #endregion }
1.先說明下這個實現演算法--逆波蘭運算式
運算式一般由運算元(Operand)、運算子(Operator)組成,例如算術運算式中,通常把運算子放在兩個運算元的中間,
這稱為中綴運算式(Infix Expression),如A+B。
波蘭數學家Jan Lukasiewicz提出了另一種數學標記法,它有兩種表示形式:
把運算子寫在運算元之前,稱為波蘭運算式(Polish Expression)或首碼運算式(Prefix Expression),如+AB;
把運算子寫在運算元之後,稱為逆波蘭運算式(Reverse Polish Expression)或尾碼運算式(Suffix Expression),如AB+;
其中,逆波蘭運算式在編譯技術中有著普遍的應用。
演算法:
一、 將中綴運算式轉換成尾碼運算式演算法:
1、從左至右掃描一中綴運算式。
2、若讀取的是運算元,則判斷該運算元的類型,並將該運算元存入運算元堆棧
3、若讀取的是運算子
(1) 該運算子為左括弧"(",則直接存入運算子堆棧。
(2) 該運算子為右括弧")",則輸出運算子堆棧中的運算子到運算元堆棧,直到遇到左括弧為止。
(3) 該運算子為非括弧運算子:
(a) 若運算子堆棧棧頂的運算子為括弧,則直接存入運算子堆棧。
(b) 若比運算子堆棧棧頂的運算子優先順序高或相等,則直接存入運算子堆棧。
(c) 若比運算子堆棧棧頂的運算子優先順序低,則輸出棧頂運算子到運算元堆棧,並將當前運算子壓入運算子堆棧。
4、當運算式讀取完成後運算子堆棧中尚有運算子時,則依序取出運算子到運算元堆棧,直到運算子堆棧為空白
樣本:
(1.2+3.5)*2/4 =>1.2 3.5+ 2* 4/
下面給出實現代碼:
C#解析字串公式