[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. 解决跨站脚本注入,跨站伪造用户请求,sql注入等http安全漏洞

    跨站脚本就是在url上带上恶意的js关键字然后脚本注入了,跨站伪造用户请求就是没有经过登陆,用超链接或者直接url上敲地址进入系统,类似于sql注入这些都是安全漏洞. sql注入 1.参数化查询预处理 ...

  2. cJSON使用

    cJSON是使用C语言编写的   关于JSON数据的   编解码库,使用方便简单 编译时注意后面要跟-lm参数,否则编译会报错 解析JSON数据包流程: 1.调用cJSON_Parse()函数,解析J ...

  3. 如何更改wampserver的网站根目录

    我之前把网站根目录自定义为:D:/demo,现在想改为:D:www, 过程就是打开httpd.conf文件,搜索demo,然后把demo改为www,之后更改虚拟配置文件,记住D盘下一定要有www目录 ...

  4. MySQL基于binlog主从复制

    MySQL复制介绍 默认情况 下复制是异步进行的,从库也不需要一直连接到主库来同步数据 MySQL复制的数据粒度可以是主实例上所有的数据库,也可以是指定的一个或多个数据库 ,也可以是一个数据库里的指定 ...

  5. python _init_学习

    今天继续学习python,接触了_init_,感觉很好玩照着教程手写了一些代码,感觉编程语言是互通的,只是换个了形式来表达 #coding=utf-8#类似于java的构造器class Person: ...

  6. Audio Unit 基础

    如图所示,所有 iOS 音频技术都是基于 audio units.此处显示的更高级别的技术,如 Media Player,AV Foundation,OpenAL,AudioToolbox,是对 au ...

  7. php动态编辑zlib扩展

    linux系统上,在php已经编译安装的情况下,启用zlib扩展不是那么容易,需要动态编译 以下是编译步骤: cd ./ext/zlib mv config0.m4 config.m4 /usr/lo ...

  8. 以Apache模块的方式编译安装php-5.4.27

    为什么要安装低版本的php? 由于apc,xcache的更新版本跟不上php版本的速度,所以,我们需要安装比较稳定的php低版本程序,再安装其它与之相匹配的扩展. 开工: 新建用户及用户组 group ...

  9. iOS-image图片压缩

    ///压缩图片 + (NSData *)imageCompressToData:(UIImage *)image{ NSData *data=UIImageJPEGRepresentation(ima ...

  10. BZOJ 2141: 排队 [CDQ分治]

    题意: 交换序列中两个元素,求逆序对 做分块做到这道题...一看不是三维偏序嘛.... 作为不会树套树的蒟蒻就写CDQ分治吧.... 对时间分治...x排序...y树状数组... 交换拆成两个插入两个 ...