c# 逆波蘭式實現計算器


語文不好,不太會組織語言,希望不要太在意。

如題,先簡要介紹一下什么是逆波蘭式  通常我們在寫數學公式的時候  就是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());

  總體代碼如此

 


免責聲明!

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



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