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());

  总体代码如此

时间: 2024-11-05 02:06:53

c# 逆波兰式实现计算器的相关文章

HDU1237 简单计算器 【栈】+【逆波兰式】

版本:1.0 日期:2014.5.17 2014.6.1 版权:© 2014 kince 转载注明出处 在介绍SwitchButton之前,先来看一下系统Button是如何实现的.源码如下: @RemoteView public class Button extends TextView { public Button(Context context) { this(context, null); } public Button(Context context, AttributeSet att

逆波兰式(后缀表达式)的计算

输入 :后缀表达式(可带浮点数) 输出:double型的计算结果 代码: #include <stdio.h> #include <stdlib.h> #include <malloc.h> #define ElemType double #define Stack_Init_Size 100 #define Increase_Size 10 #define MaxBuffer 10 typedef struct sqStack { ElemType *top; Ele

使用逆波兰式进行表达式求值

中缀表达式及后缀表达式图解中说明了使用逆波兰式进行表达式求值的方法,这里使用C++进行实现.实现和原理讲解有一点不同,需要进一步进行细化. 关于将中缀表达式转换成后后缀表达式的规则: 规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分:若是符号,则判断其与栈顶符号的优先级,是右括号或优先级低于找顶符号(乘除优先加减)则栈顶元素依次出找并输出,并将当前符号进栈,一直到最终输出后缀表达式为止. 上面的规则转换成下面的执行规则: 1.遇到操作数:直接输出(添加到后缀

逆波兰式与表达式求解

/*************** 逆波兰式即后缀表示法 预处理 ---- 中序表达式->逆序表达式(infix to postfix) 算法: while(表达式非空) if (遇到操作数) 直接输出 else if (遇到操作符op) op是( 直接入栈s op是) s.push输出,直到( op是四则运算,则 if (s为空 || s.top为( || op 优先级高于 s.top) op 入栈 else s.push输出 if (!s.empty) s.push输出 计算 算法: if (

python 逆波兰式

逆波兰式,也叫后缀表达式 技巧:为简化代码,引入一个不存在的运算符#,优先级最低.置于堆栈底部 class Stack(object): '''堆栈''' def __init__(self): self._stack = [] def pop(self): return self._stack.pop() def push(self, x): self._stack.append(x) 一.表达式无括号 def solve(bds): '''不带括号,引入#运算符''' pro = dict(

逆波兰式,有关栈的问题

/*有关逆波兰式的问题,也叫后缀表达式(将运算符写在操作数之后):例如:a+b的逆波兰式为a b +;下列程序是有关数字与数字相加的,将程序简单理解为,如果是数字,那么压入栈中,如果是运算符,那么出栈,将此前压入栈中的两个数取出栈并且相加,相加后再压入栈中,以此类推(按运算符的优先级!)*/ #include <stdio.h> #include <math.h>#include <stdlib.h>#include <ctype.h>#define STA

Haskell解决逆波兰式

摘自<Haskell趣学指南- Learn You a Haskell for Great Good> {- 逆波兰式(revese polish notation, RPN): 操作符出现在操作数的后面,而不是夹在它们中间. 如我们使用 "4 3 +" 而不是 "4 + 3". -} solveRPN :: String -> Double solveRPN = head . foldl foldingFunction [] . words wh

逆波兰式

在程序设计中,可能碰到需要对字符串数学表达式求值的问题,常用的方法是解析表达式,生成二叉树,然后进行计算.编译器就是使用这种方法来解析程序中的表达式的.这种方法实现起来有点难度,需要考虑运算符的优先级,括号的配对,堆栈的使用等等.我们正常情况下看到的数学表达式如果用二叉树遍历的话,恰好是中序遍历,故叫做中序表达式.除此之外,还有前序表达式,后序表达式.如:a+b+c(中序),++abc(前序),ab+c+(后序),如果表达式含有×,/,()等就更复杂了. 后缀表达式也称逆波兰表达式 因其使表达式

codechef Transform the Expression 转换成逆波兰式

把一般式子转换成逆波兰式. 这里的都是加括号的,难度降低点. Example Input: 3 (a+(b*c)) ((a+b)*(z+x)) ((a+t)*((b+(a+c))^(c+d))) Output: abc*+ ab+zx+* at+bac++cd+^* 知道其特点就好办: 1 遇到字母一定是可以输出的 2 遇到操作符号就入栈 3 遇到括号')',就出栈一个操作符 - 注意不是所有操作符出栈 不带括号的操作区别就在于是否需要判断符号的优先级. #include <stack> #i