[Code] 中缀式转后缀式

[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. 假定输入都是合法的, 没有对不满足概要中假设的前提的非法输入进行处理.

?

原文地址:https://www.cnblogs.com/wander4096/p/8444425.html

时间: 2024-10-27 05:58:18

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

NYOJ467中缀式变后缀式

中缀式变后缀式 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 人们的日常习惯是把算术表达式写成中缀式,但对于机器来说更"习惯于"后缀式,关于算术表达式的中缀式和后缀式的论述一般的数据结构书都有相关内容可供参看,这里不再赘述,现在你的任务是将中缀式变为后缀式. 输入 第一行输入一个整数n,共有n组测试数据(n<10). 每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式的中缀式,每个运算式都是以"="结束.这个

NYOJ467 中缀式变后缀式 【栈】

中缀式变后缀式 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 人们的日常习惯是把算术表达式写成中缀式,但对于机器来说更"习惯于"后缀式,关于算术表达式的中缀式和后缀式的论述一般的数据结构书都有相关内容可供参看,这里不再赘述,现在你的任务是将中缀式变为后缀式. 输入 第一行输入一个整数n,共有n组测试数据(n<10). 每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式的中缀式,每个运算式都是以"="结束.这个

中缀式变后缀式

中缀式变后缀式 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 人们的日常习惯是把算术表达式写成中缀式,但对于机器来说更"习惯于"后缀式,关于算术表达式的中缀式和后缀式的论述一般的数据结构书都有相关内容可供参看,这里不再赘述,现在你的任务是将中缀式变为后缀式. 输入 第一行输入一个整数n,共有n组测试数据(n<10). 每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式的中缀式,每个运算式都是以"="结束.这个

南阳OJ 中缀式变后缀式

 /*中缀式变后缀式 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 人们的日常习惯是把算术表达式写成中缀式,但对于机器来说更"习惯于"后缀式, 关于算术表达式的中缀式和后缀式的论述一般的数据结构书都有相关内容可供参看, 这里不再赘述,现在你的任务是将中缀式变为后缀式. 输入第一行输入一个整数n,共有n组测试数据(n<10). 每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式的中缀式, 每个运算式都是以"=&quo

栈的应用 — 中缀式转后缀式

由中缀式转换成后缀式,同样使用栈,并运用一些规则来完成.规则介绍如下: 当读到的是操作数,立即输出. 当读到的是运算符,则先从栈中弹出优先级高于自己的运算符(不包含括号),自己入栈. 读到左括号入栈,读到右括号则将栈中元素出栈并输出,直到遇见左括号(括号都不输出). 输入为空后,将栈元素弹出并输出直到栈空. 注意,最后生成的后缀表达式是考虑了运算符优先级的,再配合逆波兰的无优先级概念这一性质,就能够编写出一个带运算符优先级和括号的简易计算器了. 下面是完整的计算器代码,整型四则运算,可加括号.写

NYOJ 467 中缀式变后缀式

做了表达式求值那道题之后做的 时间限制:1000 ms  |  内存限制:65535 KB 难度:3 描述 人们的日常习惯是把算术表达式写成中缀式,但对于机器来说更"习惯于"后缀式,关于算术表达式的中缀式和后缀式的论述一般的数据结构书都有相关内容可供参看,这里不再赘述,现在你的任务是将中缀式变为后缀式. 输入 第一行输入一个整数n,共有n组测试数据(n<10). 每组测试数据只有一行,是一个长度不超过1000的字符串,表示这个运算式的中缀式,每个运算式都是以"=&quo

恶补C++ 之 自增、自减操作符前缀式与后缀式的区别

相信很多人刚开始学习编程的时候,也是为这个问题烦恼过吧,前缀式与后缀式,在很久之前,式没有办法区别++和--操作符的前缀和后缀的调用的.不过在C++已经得到了扩展. 然而无论式前缀或者后缀,都只有一个参数.为了解决这个问题,C++规定后缀形式有一个int类型的参数,当函数被调用的时候,编译器传递一个0作为int参数给该函数: class UPInt { public: UPInt& operator++();        // ++前缀 const UPInt operator++(int);

算法题:四则运算(中缀式到后缀式的转换,值得思考的逆波兰式)

/* 字符串的四则运算.给出一个字符串, 包含0~9的数字和 + -*\/ ()的运算符, - 仅代表减号不代表负数.举例如下: 输入:1 + 2 * (3 - 4) */ //哈哈,看到这道题,其实一点也不难,这个题根本就不用思考, //当然是你明白算法之后,这里要用到的算法是逆波兰式. //如果你有不明白的地方,可以上网搜逆波兰式. /* 我的总结:计算机无法理解人类的正向思维,于是为了满足计算机的 思维,我们会反其道而行之,将操作符号放在操作数的后面,形成后缀 表达式,但是如果你能按百科上

表达式求值(中缀式转后缀式,后缀式求值)NYOJ53测试通过

测试地址:http://acm.nyist.net/JudgeOnline/problem.php?pid=35 package calc; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Scanner; public class Main { //操作符栈 static LinkedList<String>