jjzjj

用栈模拟计算器以及中缀转后缀表达式(逆波兰表达式)

wyh518 2023-04-18 原文

后缀表达式(逆波兰表达式)运算方法

  • 从左向右读取表达式

    • 遇到数字就压入栈中
    • 遇到运算符就弹出栈顶和次顶元素。用次顶元素 运算符 栈顶元素,并将运算结果压入栈中,直到栈为空,最终结果就是运算结果

设计

中缀表达式转后缀表达式

  • 从左向右读取中缀表达式,并且创建栈s1队列s2 (因为s2只存不取且还要考虑出栈后逆序的问题,所以这里用队列来代替栈)
  • 如果读到的元素的数字,就直接入队放入s2中
  • 如果读到的是运算符(运算符判定)
    • 如果s1为空,则将该运算符压入s1
    • 如果s1不为空
      • 如果该运算符为左括号,则直接压入s1
      • 如果该运算符为右括号,则将s1中的元素依次出栈并入队到s2中,直到遇见左括号为止(括号不放入s2中)
      • 如果该运算符的优先级高于s1栈顶的运算符,则将该元素压入s1
      • 如果该运算符的优先级小于等于s1栈顶的运算符,则弹出s1栈顶的元素,并将其放入s2中,该运算符重新判定入栈操作(运算符判定步骤)
  • 如果中缀表达式已经读取完毕,则将s1中的元素依次出栈,放入s2中
  • s2中的元素依次出队,该顺序即为后缀表达式

 

 代码

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

public class PoiandNotation {
    public static void main(String[] args) {
        String expression = "1+((2+3)*4)-5";//定义一个中缀表达式
        List<String> infixExpressionList = toInfixExpressionList(expression);
        System.out.println("中缀表达式的list="+infixExpressionList);
        List<String> suffixExpreesionList = parseSuffixExpreesionList(infixExpressionList);
        System.out.println("后缀表达式的List="+suffixExpreesionList);

        System.out.println("expression的结果为: " + calculate(suffixExpreesionList));

    }

    /**
     * 将中缀表达式转化为后缀表达式(逆波兰表达式)
     * @param ls 传入的中缀表达式list集合
     * @return
     */
    public static List<String> parseSuffixExpreesionList(List<String> ls){
        Stack<String> s1 = new Stack<>();//用于暂存运算符
        List<String> s2 = new ArrayList<>();//用于存放逆波兰表达式,因为只存不取且还要考虑出栈后逆序的问题,所以这里用集合来代替栈

        for (String item : ls){//循环遍历中缀表达式的每一个元素
            if (item.matches("\\d+")){//多位数的情况直接入s2
                s2.add(item);
            }else if (item.equals("(")){
                s1.push(item);
            }else if (item.equals(")")){//碰到右括号时,s1一直出栈到s2里,直到碰到左括号为止
                while (!s1.peek().equals("(")){
                    s2.add(s1.pop());
                }
                s1.pop();//取出左括号
            }else {
                while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)){
                    //当s1栈顶运算符优先级大于或等于当前扫描到的运算符优先级,则出栈放入s2
                    s2.add(s1.pop());
                }
                s1.push(item);//把当前扫描到的运算符入栈到s1
            }
        }
        //将s1剩余的运算符全部放入s2
        while (s1.size() != 0){
            s2.add(s1.pop());
        }

        return s2;
    }

    /**
     * 将一个中缀表达式以集合的形式输入
     * @param s 输入的中缀表达式
     * @return
     */
    public static List<String> toInfixExpressionList(String s){
        List<String> ls = new ArrayList<>();
        int i = 0;//用于扫描中缀表达式
        char c;//把每一个扫描到的字符存到c里
        String str;//用与拼接字符,存储多位数

        do {
            if ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57){//如果不是数字,就直接放入集合中
                ls.add("" + c);
                i++;
            }else {
                str = "";//初始化
                while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57){//是数字则还要判断是否为多位数的情况
                    str += c;
                    i++;
                }
                ls.add(str);
            }
        }while (i < s.length());
        return ls;
    }

    /**
     * 用于计算后缀表达式
     * @param getSuffixList 接收后缀表达式的集合
     * @return
     */
    public static int calculate(List<String> getSuffixList){
        Stack<String> stack = new Stack<>();

        for (String item : getSuffixList) {
            if (item.matches("\\d+")){//如果是数字就直接入栈
                stack.push(item);
            }else {
                int num2 = Integer.parseInt(stack.pop());
                int num1 = Integer.parseInt(stack.pop());
                int res = 0;

                if (item.equals("+")){
                    res = num1 + num2;
                }else if (item.equals("-")){
                    res = num1-num2;
                }else if (item.equals("*")){
                    res = num1 * num2;
                }else if (item.equals("/")){
                    res = num1 / num2;
                }
                stack.push("" + res);
            }
        }
        return Integer.parseInt(stack.pop());
    }
}

//定义运算符的优先级
class Operation{
    private static int ADD = 1;
    private static int SUB = 1;
    private static int MUL = 2;
    private static int DIV = 2;

    public static int getValue(String operation){
        int result = 0;
        switch (operation){
            case "+":
                result = ADD;
                break;
            case "-":
                result = SUB;
                break;
            case "*":
                result = MUL;
                break;
            case "/":
                result = DIV;
                break;
            default:
                System.out.println("不存在该运算符");
                break;
        }
        return result;
    }
}

  结果

 

有关用栈模拟计算器以及中缀转后缀表达式(逆波兰表达式)的更多相关文章

  1. ruby - 什么是填充的 Base64 编码字符串以及如何在 ruby​​ 中生成它们? - 2

    我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%

  2. ruby 正则表达式 - 如何替换字符串中匹配项的第 n 个实例 - 2

    在我的应用程序中,我需要能够找到所有数字子字符串,然后扫描每个子字符串,找到第一个匹配范围(例如5到15之间)的子字符串,并将该实例替换为另一个字符串“X”。我的测试字符串s="1foo100bar10gee1"我的初始模式是1个或多个数字的任何字符串,例如,re=Regexp.new(/\d+/)matches=s.scan(re)给出["1","100","10","1"]如果我想用“X”替换第N个匹配项,并且只替换第N个匹配项,我该怎么做?例如,如果我想替换第三个匹配项“10”(匹配项[2]),我不能只说s[matches[2]]="X"因为它做了两次替换“1fooX0barXg

  3. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  4. 【鸿蒙应用开发系列】- 获取系统设备信息以及版本API兼容调用方式 - 2

    在应用开发中,有时候我们需要获取系统的设备信息,用于数据上报和行为分析。那在鸿蒙系统中,我们应该怎么去获取设备的系统信息呢,比如说获取手机的系统版本号、手机的制造商、手机型号等数据。1、获取方式这里分为两种情况,一种是设备信息的获取,一种是系统信息的获取。1.1、获取设备信息获取设备信息,鸿蒙的SDK包为我们提供了DeviceInfo类,通过该类的一些静态方法,可以获取设备信息,DeviceInfo类的包路径为:ohos.system.DeviceInfo.具体的方法如下:ModifierandTypeMethodDescriptionstatic StringgetAbiList​()Obt

  5. ruby - 正则表达式将非英文字母匹配为非单词字符 - 2

    @raw_array[i]=~/[\W]/非常简单的正则表达式。当我用一些非拉丁字母(具体来说是俄语)尝试时,条件是错误的。我能用它做什么? 最佳答案 @raw_array[i]=~/[\p{L}]/使用西里尔字符进行测试。引用:http://www.regular-expressions.info/unicode.html#prop 关于ruby-正则表达式将非英文字母匹配为非单词字符,我们在StackOverflow上找到一个类似的问题: https://

  6. 阿里云国际版免费试用:如何注册以及注意事项 - 2

    作为新的阿里云用户,您可以50免费试用多种优惠,价值高达1,700美元(或8,500美元)。这将让您了解和体验阿里云平台上提供的一系列产品和服务。如果您以个人身份注册免费试用,您将获得价值1,700美元的优惠。但是,如果您是注册公司,您可以选择企业免费试用,提交基本信息通过企业实名注册验证,即可开始价值$8,500的免费试用!本教程介绍了如何设置您的帐户并使用您的免费试用版。​关于免费试用在我们开始此试用之前,您还必须遵守以下条款和条件才能访问您的免费试用:只有在一年内创建的账户才有资格获得阿里云免费试用。通过此免费试用优惠,用户可以免费试用免费试用活动页面上列出的每种产品一次。如果您有多个帐

  7. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  8. ruby - 有没有办法从 ruby​​ case 语句中访问表达式? - 2

    我想从then子句中访问c​​ase语句表达式,即food="cheese"casefoodwhen"dip"then"carrotsticks"when"cheese"then"#{expr}crackers"else"mayo"end在这种情况下,expr是食物的当前值(value)。在这种情况下,我知道,我可以简单地访问变量food,但是在某些情况下,该值可能无法再访问(array.shift等)。除了将expr移出到局部变量然后访问它之外,是否有直接访问caseexpr值的方法?罗亚附注我知道这个具体示例很简单,只是一个示例场景。 最佳答案

  9. ruby - 正则表达式 - 排除一个字符 - 2

    这是一个例子:s="abcd+subtext@example.com"s.match(/+[^@]*/)Result=>"+subtext"问题是,我不想在其中包含“+”。我希望结果是“潜台词”,没有+ 最佳答案 您可以在正则表达式中使用括号来创建匹配组:s="abcd+subtext@example.com"s=~/\+([^@]*)/&&$1=>"subtext" 关于ruby-正则表达式-排除一个字符,我们在StackOverflow上找到一个类似的问题:

  10. ruby-on-rails - 在这种情况下我如何模拟一个对象?没有明显的方法可以用模拟替换对象 - 2

    假设我在Store的模型中有这个非常简单的方法:defgeocode_addressloc=Store.geocode(address)self.lat=loc.latself.lng=loc.lngend如果我想编写一些不受地理编码服务影响的测试脚本,这些脚本可能已关闭、有限制或取决于我的互联网连接,我该如何模拟地理编码服务?如果我可以将地理编码对象传递到该方法中,那将很容易,但我不知道在这种情况下该怎么做。谢谢!特里斯坦 最佳答案 使用内置模拟和stub的rspecs,你可以做这样的事情:setupdo@subject=MyCl

随机推荐