[Code] 中缀式转后缀式

概要

对于一个可带括号的中缀四则运算表达式, 例如30 + 4 / 230 / ( 4 + 2 ), 下面代码将分别转换为对应的后缀表达形式 30 4 2 / +30 4 2 + /. 要求每个 token 之间以若干个空白符隔开, 输入的中缀式为单行.

代码

import java.util.Scanner;
import java.util.Deque;
import java.util.ArrayDeque;
import java.util.Map;

public class Convertor {
  public static void main(String[] main) {
    Scanner in = new Scanner(System.in);
    String expression = in.nextLine();
    expression = "( " + expression + " )";
    String[] tokens = expression.split("\\s+");

    Deque<String> opStack = new ArrayDeque<>();
    Deque<String> nuStack = new ArrayDeque<>();

    Map<String, Integer> opPriority =
      Map.of("+", 0, "-", 0, "*", 1, "/", 1, "(", -1);

    for (String token: tokens) {
      if (token.equals("(")) {
        opStack.addFirst(token);
      } else if (token.equals(")")) {
        while (!opStack.peekFirst().equals("(")) {
          produceOne(opStack, nuStack);
        }
        opStack.removeFirst();
      } else if (opPriority.containsKey(token)) {
        while ((!opStack.isEmpty()) && (opPriority.get(token) <=  opPriority.get(opStack.peekFirst()))) {
          produceOne(opStack, nuStack);
        }
        opStack.addFirst(token);
      } else { // number
        nuStack.addFirst(token);
      }
    }
    System.out.println(nuStack.removeFirst().replaceAll("\\s+", " ").trim());
  }

  private static void produceOne(Deque<String> opStack, Deque<String> nuStack) {
    String production = filter(nuStack.removeFirst()) + " ";
    production = filter(nuStack.removeFirst()) + " " + production + " ";
    production = production + " " + opStack.removeFirst() + " ";
    nuStack.addFirst(production);
  }

  private static String filter(String token) {
    return token.equals("@") ? "" : token;
  }
}

分析

  1. 为了统一处理(避免分类讨论), 对于输入的中缀表达式直接加上两端的括号. 这样的操作并不会影响整个求解的结果, 而不加这个括号需要额外处理最终操作符栈剩余的操作符.
  2. 逐个 token 处理,
    1. 对于操作数, 直接入栈.
    2. 左右括号配对处理.
    3. 对于一般的操作符, 在此处充当 trigger 的作用. 逻辑上, 第一个操作符入栈, 对于后续的操作符, 先逐个弹出操作符栈中优先级不小于当前操作符的运算符以及相应的操作数, 在将当前的操作符入栈. 弹出优先级大的操作符是显然的, 弹出优先级相等的操作符是由于要满足左结合性, 若是右结合操作符, 则不弹出. 注意弹出操作符并产生代表运算结果的字符串后仍需将其当做结果压回操作数栈中.
  3. 细节上,
    1. 使用 Java 9 的 Map.of 函数简化 opPriority 字典的构建代码.
    2. 使用效率更高实现更完备的 Deque 并将操作限制在栈操作上以代替不再推荐的 Stack.
    3. 为了简化讨论, 将 ( 的优先级定义为最低.
    4. 为了简化讨论, 先在各结果 token 之间插入若干个空白符, 输出时再统一压缩多余的空白符.
  4. 假定输入都是合法的, 没有对不满足概要中假设的前提的非法输入进行处理.

[Code] 中缀式转后缀式的更多相关文章

  1. NYOJ467 中缀式变后缀式 【栈】

    中缀式变后缀式 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描写叙述 人们的日常习惯是把算术表达式写成中缀式,但对于机器来说更"习惯于"后缀式.关于算术 ...

  2. NYOJ 467 中缀式变后缀式

    做了表达式求值那道题之后做的 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描写叙述 人们的日常习惯是把算术表达式写成中缀式,但对于机器来说更"习惯于"后 ...

  3. nyoj 467 中缀式变后缀式 (栈)

    中缀式变后缀式 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 人们的日常习惯是把算术表达式写成中缀式,但对于机器来说更“习惯于”后缀式,关于算术表达式的中缀式和后缀 ...

  4. NYOJ--257--郁闷的C小加(一)(中缀表达式变后缀表达式 )

    郁闷的C小加(一) 时间限制:1000 ms  |  内存限制:65535 KB 难度:3   描述 我们熟悉的表达式如a+b.a+b*(c+d)等都属于中缀表达式.中缀表达式就是(对于双目运算符来说 ...

  5. 栈的简单应用之中缀表达式转后缀表达式(C语言实现逆波兰式)

    一.前言   普通人在书写计算式时会选择中缀表达式,这样符合人脑的认知习惯.可计算机处理时后缀表达式才能使处理速度更快,其原因是利用堆栈结构减少计算机内存访问.同时它也是一个很好锻炼栈这个数据结构的应 ...

  6. SDUT 2133 数据结构实验之栈三:后缀式求值

    数据结构实验之栈三:后缀式求值 Time Limit: 1000ms   Memory limit: 65536K  有疑问?点这里^_^ 题目描述 对于一个基于二元运算符的后缀表示式(基本操作数都是 ...

  7. SDUT-2133_数据结构实验之栈与队列三:后缀式求值

    数据结构实验之栈与队列三:后缀式求值 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 对于一个基于二元运算符的后缀表示式 ...

  8. SDUT-2132_数据结构实验之栈与队列二:一般算术表达式转换成后缀式

    数据结构实验之栈与队列二:一般算术表达式转换成后缀式 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 对于一个基于二元运 ...

  9. javascript使用栈结构将中缀表达式转换为后缀表达式并计算值

    1.概念 你可能听说过表达式,a+b,a+b*c这些,但是前缀表达式,前缀记法,中缀表达式,波兰式,后缀表达式,后缀记法,逆波兰式这些都是也是表达式. a+b,a+b*c这些看上去比较正常的是中缀表达 ...

随机推荐

  1. Java常用类--处理日期

    Date Date类在java.util包中.使用Date类的无参数构造方法创建的对象可以获取本地当前时间.一般来说,也只使用这个.因为date的很多方法都已经不推荐使用了,所以Date的功能大大的消 ...

  2. 06_Ajax初步入门第一天

    视频来源:麦子学院 讲师:李毅 ajax:异步JavaScript和XML,局部刷新 原生ajax实例 创建对象 XMLHttpRequest对象 request=new XMLHttpRequest ...

  3. 【PHP】学习中遇到的php方法

    [1]range()快速创建一个范围内数组 <?php range(0,20); 创建一个包含从 "0" 到 "20" 之间的元素范围的数组: range ...

  4. 开发JQuery插件(转)

    教你开发jQuery插件(转)   阅读目录 基本方法 支持链式调用 让插件接收参数 面向对象的插件开发 关于命名空间 关于变量定义及命名 压缩的好处 工具 GitHub Service Hook 原 ...

  5. 使用mybatis从mysql里进行模糊查询的编码问题

    关于这个问题,记录下我的解决方法,希望对有同样困惑的朋友,有所帮助. 问题描述: 我在做mybatis从mysql里模糊查询时,如果模糊的关键词是字母的话,可以查出来.如果模糊的关键词是汉字的话,查不 ...

  6. java之静态代理和动态代理

    我们以几个问题,来开始我们今天的学习,如果下面几个问题,你都能说出个一二,那么恭喜你,你已经掌握了这方面的知识.1,什么是代理模式?2,Java中,静态代理与动态代理的区别?3,Spring使用的是J ...

  7. cookie和session的那些事

    对于经常网购的朋友来说,经常会遇到一种情况: 打开淘宝或京东商城的首页,输入个人账号和密码进行登陆,然后进行购物,支付等操作都不需要用户再次输入用户名和密码 但是如果用户换一个浏览器或者等几个小时后再 ...

  8. LVS、Nginx和HAProxy负载均衡器对比总结

    LVS特点: 1.抗负载能力强,使用IP负载均衡技术,只做分发,所以LVS本身并没有多少流量产生: 2.稳定性.可靠性好,自身有完美的热备方案:(如:LVS+Keepalived) 3.应用范围比较广 ...

  9. 什么是SSL

    什么是SSL 简单来说,在我们使用的浏览器中都默认信任着全世界多个最权威的CA机构(证书颁发机构),如下图: 上图中,受信任的根证书颁发机构列表里的都是我们浏览器中默认信任的CA机构,我们只需要向他们 ...

  10. java中的各种Queue

    java中的各种并发Queue可以归为以下的几种: ConcurrentLinkedQueue: 一个由链表结构组成的非阻塞队列 ArrayBlockingQueue :一个由数组结构组成的有界阻塞队 ...