基于中缀表达式和后缀表达式的计算器

基于中缀表达式和后缀表达式的计算器

中缀表达式计算器

使用栈完成表达式的计算思路:

  1. 设置两个空栈:

    • 数栈 n u m S t a c k numStack numStack:用于存放数
    • 运算符栈 o p e r a t o r S t a c k operatorStack operatorStack:用于存放运算符
  2. 通过一个 i n d e x index index值遍历表达式

  3. 若为数,则直接入数栈

  4. 若为运算符,分以下情况:

    1. 如果当前符号栈为空,则直接入符号栈
    2. 如果符号栈有操作符,就进行比较
      • 当前操作符的优先级小于等于栈中操作符,从数栈中pop出两个数,在运算符栈中pop出一个符号进行运算,将运算结果压入数栈,然后将当前运算符压入运算符栈.
      • 当前运算符的优先级大于栈中的运算符,直接压入运算符栈
  5. 当表达式扫描完毕,就顺序从数栈和符号栈中pop出响应的数和符号,并运行

  6. 最后数栈中只剩下一个数字,就是表达式的结果

缺点:不方便识别括号

前缀、中缀、后缀表达式

前缀表达式

例如: ( 3 + 4 ) × 5 − 6 (3+4)\times5-6 (3+4)×56 对应的前缀表达式为: −   ×   +   3   4   5   6 -\,\times\,+\,3\,4\,5\,6 ×+3456

计算机求值:

  • 设置一个数栈

  • 从右到左扫描表达式,遇到数字的时候,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用当前运算符对它们做相应的计算(栈顶元素和次顶元素,注意顺序:栈顶元素为 n u m 1 num1 num1,次顶元素为 n u m 2 num2 num2),并将结果压入栈;

  • 重复上述过程,最后栈中只剩下一个元素,将其pop出来作为运算结果

中缀表达式

中缀表达式就是我们平时所见到的表达式,如: ( 3 + 4 ) × 5 − 6 (3+4)\times5-6 (3+4)×56

中缀表达式的求值是我们人最熟悉的,但是对于计算机来讲并不好操作.因此在计算结果时,往往会将中缀表达式转化为其他表达式来操作(一般是转化成后缀表达式)

后缀表达式(逆波兰表达式)

后缀表达式又称为逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后(最符合计算机的思考方式)

举例说明:

( 3 + 4 ) × 5 − 6 (3+4)\times5-6 (3+4)×56对应的后缀表达式为 3   4   +   5   ×   6   − 3\,4\,+\,5\,\times\,6\,- 34+5×6

计算过程:

与前缀相似,只不过是从前往后扫描

中缀表达式 -> 后缀表达式

思路步骤分析:

  1. 初始化两个栈,运算符栈 s 1 s_1 s1和存储中间结果的栈 s 2 s_2 s2
  2. 从左到右扫描中缀表达式
  3. 遇到操作数直接压入 s 2 s_2 s2
  4. 遇到运算符,比较其与 s 1 s_1 s1栈顶运算符的优先级(小括号不纳入运算符)
    1. 如果 s 1 s_1 s1为空,或者栈顶元素为左括号"(",则直接将当前运算符压入 s 1 s_1 s1
    2. 若优先级高于 s 1 s_1 s1栈顶运算符,也将当前运算符压入 s 1 s_1 s1
    3. 若不满足以上两个条件,将 s 1 s_1 s1栈顶元素弹出并压入 s 2 s_2 s2中,再次转至4.1,当前运算符与新的栈顶运算符相比较
  5. 遇到括号
    1. 如果是左括号"(",则直接压入 s 1 s_1 s1
    2. 如果是右括号")“,则依次弹出 s 1 s_1 s1栈顶的运算符,并压入 s 2 s_2 s2,直到遇到左括号”(“,此时将这一对括号丢弃(这样的操作决定了 s 1 s_1 s1中不可能有右括号”)")
  6. 重复步骤2~5,直至表达式的最右边
  7. s 1 s_1 s1中剩余的运算符依次弹出并压入 s 2 s_2 s2
  8. 依次弹出 s 2 s_2 s2的元素并输出,结果的逆序即为对应的后缀表达式

简化:注意 s 2 s_2 s2在整个操作期间没有pop操作,只有压栈操作,故没必要再设定一个 s 2 s_2 s2栈(结束后需要全部弹出并且逆序).故 s 2 s_2 s2可以直接设置成 A r r a y L i s t ArrayList ArrayList省去弹出并逆序的操作.

中缀表达式计算器

完整代码:

import java.util.ArrayList;
import java.util.Stack;

public class Calculator
{
    public static void main(String[] args)
    {
        Calculator calculator = new Calculator("1+2*7.5-3/2");
        System.out.println(calculator.getResult());
    }
    //算式字符串
    String formula;

    //构造方法
    public Calculator(String formula)
    {
        this.formula = formula;
    }

    public double getResult()
    {
        //数栈
        Stack<Double> numStack = new Stack<>();
        //运算符栈
        Stack<String> operStack = new Stack<>();
        //所有元素放再elements中
        ArrayList<String> elements = divideElement();
        int cur = 0;
        while(cur < divideElement().size())
        {
            String s = elements.get(cur);
            //是数字直接压入数字栈
            if(!isOperator(s))
            {
                numStack.push(Double.parseDouble(s));
            }
            else
            {
                //运算符栈为空,则直接压入运算符栈
                if(operStack.isEmpty())
                {
                    operStack.push(s);
                    cur++;
                    continue;
                }
                String oper1 = s;       //oper1为当前运算符
                String oper2 = operStack.peek();    //oper2为运算符栈顶运算符
                if(compareOper(oper1,oper2) == -1)  //oper1优先级小于等于oper2
                {
                    //先从数栈中弹出两个数,进行计算后,压入数栈
                    oper2 = operStack.pop();
                    double num2 = numStack.pop();
                    double num1 = numStack.pop();
                    numStack.push(calculate(num1,oper2,num2));
                    //再将当前运算符压入运算符栈
                    operStack.push(oper1);
                }
                else        //oper1优先级大于oper2
                {
                    operStack.push(oper1);
                }
            }
            cur++;
        }
        //将数栈和运算符栈中所有的元素取出,一一计算
        while(!operStack.isEmpty())
        {
            double num2 = numStack.pop();
            double num1 = numStack.pop();
            String oper = operStack.pop();
            numStack.push(calculate(num1,oper,num2));
        }
        //最后数栈中剩下的元素即为结果
        return numStack.pop();
    }

    //将所有元素(数,运算符)拆分至一个ArrayList中
    public ArrayList<String> divideElement()
    {
        int cur = 0;
        ArrayList<String> elements = new ArrayList<>();
        while(cur < formula.length())
        {
            Character c = formula.charAt(cur);
            //运算符只有一个字符,直接压入
            if(isOperator(c))
            {
                elements.add(c.toString());
                cur++;
            }
            //默认除运算符以外的所有元素都为数字
            else
            {
                //捕获的所有数字符号拼接到一个StringBuilder中
                StringBuilder sb = new StringBuilder();
                while(cur < formula.length() && !isOperator(formula.charAt(cur)) )
                {
                    sb.append(formula.charAt(cur));
                    cur++;
                }
                //将StringBuilder转化为字符串添加至ArrayList中
                elements.add(sb.toString());
            }
        }
        return elements;
    }

    //判断是否为运算符
    //字符
    public boolean isOperator(Character c) { return c == '+' || c == '-' || c == '*' || c == '/'; }
    //字符串(重写)
    public boolean isOperator(String s) { return s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/"); }

    //比较运算符优先级(oper1 - oper2),oper1大于oper2则返回1,否则返回-1
    public static int compareOper(String oper1,String oper2)
    {
        //如果运算符1为"+"或"-",则无论oper2是什么,oper1的优先级都不会比oper2大,返回-1
        if(oper1.equals("+") || oper1.equals("-"))
        {
            return -1;
        }
        else
        {
            if(oper2.equals("+") || oper2.equals("-"))
            {
                return 1;
            }
            else
            {
                return -1;
            }
        }
    }

    //计算两数
    public static double calculate(double num1,String oper,double num2)
    {
        switch (oper)
        {
            case "+": { return num1 + num2; }
            case "-": { return num1 - num2; }
            case "*": { return num1 * num2; }
            case "/": { return num1 / num2; }
            //只能识别加减乘除,其他的预算符则抛出异常
            default: { throw new RuntimeException("运算符无效!"); }
        }
    }
}

后缀表达式计算器

完整代码:

import java.util.ArrayList;
import java.util.Stack;

public class PolandCalculator
{
    public static void main(String[] args)
    {
        PolandCalculator calculator = new PolandCalculator("(1+2.5)*3-4*((5-1*2)-2)");
        System.out.println(calculator.getResult());
    }

    //算式字符串
    String formula;

    //构造方法
    public PolandCalculator(String formula)
    {
        this.formula = formula;
    }

    //将所有元素(数,运算符)拆分至一个ArrayList中
    public ArrayList<String> divideElement()
    {
        int cur = 0;
        ArrayList<String> elements = new ArrayList<>();
        while(cur < formula.length())
        {
            Character c = formula.charAt(cur);
            if(isOperator(c) || c == '(' || c == ')')
            {
                elements.add(c.toString());
                cur++;
            }
            else
            {
                StringBuilder sb = new StringBuilder();
                while(cur < formula.length() && !(isOperator(formula.charAt(cur)) || formula.charAt(cur)=='(' || formula.charAt(cur)==')') )
                {
                    sb.append(formula.charAt(cur));
                    cur++;
                }
                elements.add(sb.toString());
            }
        }
        return elements;
    }

    //中缀表达式转后缀表达式
    public ArrayList<String> infixToSuffix(ArrayList<String> infix)
    {
        Stack<String> s1 = new Stack<>();
        //s2没有弹出操作,因此可以直接定义成ArrayList(因为如果使用栈的话,全部弹出后还需要反转)
        ArrayList<String> s2 = new ArrayList<>();
        int cur = 0;
        while(cur < infix.size())
        {
            String s = infix.get(cur);
            //如果是操作数,直接压入s2
            if(!(isOperator(s) || s.equals("(") || s.equals(")")))
            {
                s2.add(s);
            }
            else
            {
                //是运算符
                if(isOperator(s))
                {
                    while(true)
                    {
                        //s1为空,或者当前运算符优先级大于s1栈顶运算符
                        if (s1.isEmpty() || s1.peek().equals("(") || compareOper(s, s1.peek()) == 1)
                        {
                            s1.push(s);
                            break;
                        }
                        //运算符优先级小于等于s1栈顶运算符,将s1栈顶弹出并交付至s2中,继续循环
                        else
                        {
                            s2.add(s1.pop());
                        }
                    }
                }
                //是括号
                else
                {
                    //左括号直接压入
                    if(s.equals("("))
                    {
                        s1.push(s);
                    }
                    //右括号进行以下操作
                    else
                    {
                        while(!s1.peek().equals("("))
                        {
                            s2.add(s1.pop());
                        }
                        s1.pop();
                    }
                }
            }
            cur++;
        }
        while(!s1.isEmpty())
        {
            s2.add(s1.pop());
        }
        //s2即为最终的后缀表达式,返回s2
        return s2;
    }

    //计算结果
    public double getResult()
    {
        ArrayList<String> infix = divideElement();
        ArrayList<String> suffix = infixToSuffix(infix);
        //用一个栈存储中间结果
        Stack<Double> numStack = new Stack<>();
        for (String s:suffix)
        {
            //是运算符则取出两数进行计算
            if(isOperator(s))
            {
                double num2 = numStack.pop();
                double num1 = numStack.pop();
                numStack.push(calculate(num1,s,num2));
            }
            //是数则直接转化成double压入栈
            else
            {
                numStack.push(Double.parseDouble(s));
            }
        }
        return numStack.pop();
    }

    //判断是否为运算符
    //字符
    public boolean isOperator(Character c)
    {
        return c == '+' || c == '-' || c == '*' || c == '/';
    }
    //字符串(重写)
    public boolean isOperator(String s) { return s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/"); }

    //比较运算符优先级(oper1 - oper2),oper1大于oper2则返回1,否则返回-1
    public static int compareOper(String oper1,String oper2)
    {
        //如果运算符1为"+"或"-",则无论oper2是什么,oper1的优先级都不会比oper2大,返回-1
        if(oper1.equals("+") || oper1.equals("-"))
        {
            return -1;
        }
        else
        {
            if(oper2.equals("+") || oper2.equals("-"))
            {
                return 1;
            }
            else
            {
                return -1;
            }
        }
    }

    //计算两数
    public static double calculate(double num1,String oper,double num2)
    {
        switch (oper)
        {
            case "+": { return num1 + num2; }
            case "-": { return num1 - num2; }
            case "*": { return num1 * num2; }
            case "/": { return num1 / num2; }
            //只能识别加减乘除,其他的预算符则抛出异常
            default: { throw new RuntimeException("运算符无效!"); }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
中缀表达式后缀表达式是一种用于计算数学表达式的方法。在后缀表达式中,操作符位于操作数的后面。为了实现这个计算器,我们可以使用栈数据结构作为辅助工具。 首先,我们需要定义一个函数,这个函数会接收中缀表达式作为参数,并返回对应的后缀表达式。在这个函数中,我们可以遍历中缀表达式的每个元素。对于数字,我们可以直接将其添加到后缀表达式中。对于操作符,我们需要根据其优先级来判断是否需要将其弹出栈并添加到后缀表达式中。 具体步骤如下: 1. 创建一个空栈和一个空结果列表。 2. 遍历中缀表达式的每个元素。 3. 如果遇到数字,将其添加到结果列表中。 4. 如果遇到左括号,将其压入栈中。 5. 如果遇到右括号,将栈中的操作符弹出并添加到结果列表中,直到遇到左括号为止。 6. 如果遇到操作符,比较其与栈顶操作符的优先级:如果栈顶操作符的优先级高于等于当前操作符,则将其弹出并添加到结果列表中,重复此步骤直到栈顶操作符优先级小于当前操作符或栈为空。然后将当前操作符压入栈中。 7. 遍历完中缀表达式后,将栈中的所有操作符弹出并添加到结果列表中。 最后,返回结果列表即可得到后缀表达式。通过对后缀表达式的计算,我们可以得到最终的结果。 这个计算器可以使用C语言来实现。通过使用栈来保存操作符,并按照上述步骤进行遍历和计算,我们可以实现一个简单但有效的中缀表达式后缀表达式计算器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

#冷咖啡离开了杯垫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值