zoukankan      html  css  js  c++  java
  • 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());
    

      总体代码如此

     
  • 相关阅读:
    Git上手:四种常见的Git协同工作方式
    Git上手:Git扫盲区
    理解web缓存
    浅谈对技术债的理解
    保护个人隐私,从我做起
    cookie注意事项
    了解JavaScript核心精髓(二)
    简单实现nodejs爬虫工具
    浅谈我所见的CSS组织风格
    利用正则表达式清除多余的空行
  • 原文地址:https://www.cnblogs.com/ZyCoder/p/6696464.html
Copyright © 2011-2022 走看看