語文不好,不太會組織語言,希望不要太在意。
如題,先簡要介紹一下什么是逆波蘭式 通常我們在寫數學公式的時候 就是a+b+c這樣,這種表達式稱為中綴表達式,逆波蘭式又稱為后綴表達式,例如a+b 后綴表達式就為ab+
而把中綴表達式轉為逆波蘭式也是很容易的,以下算法摘自百度百科
簡要說一下棧,棧是一種先進后出的對象集合,可以把棧理解為一個桶,先進后出 Stack Peek()是取出但是不剔除 做比較的時候用,Pop()是出棧,Push()入棧
首先需要分配2個棧,一個作為臨時存儲運算符的棧S1(含一個結束符號),一個作為輸入逆波蘭式的棧S2(空棧),S1棧可先放入優先級最低的運算符#,注意,中綴式應以此最低優先級的運算符結束。可指定其他字符,不一定非#不可。從中綴式的左端開始取字符,逐序進行如下步驟:
(1)若取出的字符是
操作數,則分析出完整的運算數,該操作數直接送入S2棧
(2)若取出的字符是
運算符,則將該運算符與S1棧棧頂元素比較,如果該
運算符優先級大於S1棧棧頂運算符優先級,則將該運算符進S1棧,否則,將S1棧的棧頂運算符彈出,送入S2棧中,直至S1棧棧頂運算符低於(不包括等於)該運算符優先級,最后將該運算符送入S1棧。
(3)若取出的字符是“(”,則直接送入S1棧頂。
(4)若取出的字符是“)”,則將距離S1棧棧頂最近的“(”之間的運算符,逐個
出棧,依次送入S2棧,此時拋棄“(”。
(5)重復上面的1~4步,直至處理完所有的輸入字符
(6)若取出的字符是“#”,則將S1棧內所有運算符(不包括“#”),逐個出棧,依次送入S2棧。
完成以上步驟,S2棧便為逆波蘭式輸出結果。不過S2應做一下逆序處理。便可以按照逆波蘭式的計算方法計算了!把一個表達式轉為逆波蘭式 比如 (a+b)*c 逆波蘭式為ab+c*
a為數字,入棧,b為數字,入棧,“+”,為運算符 a b出棧,計算a+b 然后將結果 入棧,c入棧,"*"為運算符,a+b的結果出棧,c出棧,運算 * 將結果再入棧 運算完畢,棧里的結果就是我們想要的了
代碼實現(有點亂)
判斷元素是不是為數字
static bool IsNumber(string s) { return Regex.IsMatch(s, @"\d+"); }
判斷元素是否為運算符(+-*/)
static bool IsSiZe(string s) { string ts = "+-*/"; return ts.IndexOf(s) > -1; }
判斷優先級
static int Level(string s) { int i = 0; switch (s) { case ",": i = 0; break; case "(": case ")": case "#": i = 1; break; case "+": case "-": i = 2; break; case "*": case "/": i = 3; break; } return i; }
計算
private static void Calc(Stack<string> numStack, Stack<string> operStack) { int rightnum = int.Parse(numStack.Pop()); int leftnum = int.Parse(numStack.Pop()); string oper = operStack.Pop(); switch (oper) { case "+": numStack.Push((leftnum + rightnum).ToString()); break; case "-": numStack.Push((leftnum - rightnum).ToString()); break; case "*": numStack.Push((leftnum * rightnum).ToString()); break; case "/": numStack.Push((leftnum / rightnum).ToString()); break; } }
總體實現代碼
static void ToNiBoLan(string exp) { operStack.Push("#"); //進棧 便於比較 string token = ""; for (int i = 0; i < exp.Length; i++) { if (IsNumber(exp[i].ToString())) //如果是數字 { token += exp[i].ToString(); } else if (exp[i].ToString() == "(") //左括號直接進棧 { operStack.Push(exp[i].ToString()); if (IsNumber(token)) numStack.Push(token); token = ""; } else if (IsSiZe(exp[i].ToString())) { if (IsNumber(token)) numStack.Push(token); token = ""; int item = Level(exp[i].ToString()).CompareTo(Level(operStack.Peek())); //比較運算符優先級 if (item > 0) //如果優先級高於棧頂,運算符進棧 { operStack.Push(exp[i].ToString()); } else //如果運算符小於或等於棧頂 進行計算 並將運算符進棧 { Calc(numStack, operStack); operStack.Push(exp[i].ToString()); } } else if (exp[i].ToString() == ")") //如果遇到右括號 依次遍歷進行計算直至遇到左括號 { if (IsNumber(token)) numStack.Push(token); token = ""; while (operStack.Peek() != "(") { Calc(numStack, operStack); } token = numStack.Pop(); //拿出數字便於進行下一次計算 operStack.Pop(); //符合條件的左括號出棧 } else //遍歷結束 { if (IsNumber(token)) numStack.Push(token); token = ""; while (numStack.Count > 1) { Calc(numStack, operStack); } } } }
調用
string s = Console.ReadLine()+"#"; //為了便於比較,在表達式結尾加上"#" ToNiBoLan(s); Console.WriteLine(numStack.Pop());
總體代碼如此