【Algorithm】逆波兰表达式 Java实现
来源:互联网 发布:乐其网络骗局 编辑:程序博客网 时间:2024/05/29 11:35
简介
逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。
逆波兰表达式可以用于表达式转换,如数学公式转换计算,很早之前做过一个计算器,但是解析公式 到时候感到万分头疼,今天看到逆波兰表达式这个东西,不禁感慨:
果然,数据结构学不好是得吃大亏。
思路
对于常规的数学表达式,我们要做的是根据其优先级计算结果(小学生都知道)。
编程实现的话,其实也很简单,两个栈即可实现,姑且把一个栈叫做 operators
,保存运算符,另一个栈叫做output
,保存最终的表达式。
就三个要点:
- 数字直接入
output
- 运算符要与
operators
栈顶比较,优先级大则入栈,小于或等于则operators
出栈后再入栈 operators
栈顶若是(
则无条件入栈
下面举的这个例子,只针对简单 +
-
*
/
(
)
,别的实现,如小数,平方等操作,原理都差不多,可以自行扩展。
对这个a*(b-c*d)+e
式子来说,转成波兰表达式后应该是这样子的:abcd*-*e+
1.读到a
,将a
压入output
2.读到*
,operators
栈为空,直接将*
压入operators
3.读到(
优先级最高,无条件压入operators
4.读到b
,将b
压入output
5.读到-
,因为有(
的存在,无视比之前的*
或(
优先级低
6.读到c
,将c
压入output
7.读到*
,因为比+
的优先级高,压入operators
8.读到d
,将d
压入output
9.读到)
,将operators
中(
之后的所有运算符弹出并压入output
10.读到+
,将operators
所有栈顶优先级比+
的运算符弹出,最后将+
压入operators
11.读到e
,将e
压入output
12.表达式读取完,将output
所有运算符压入output
实现
以下代码是Java的实现,字符串解析和逆波兰表达式解析放在一起,但还是根据上面的思路来解决。
import java.util.Stack;public class ReversePolishNotation { public static void main(String[] args) { //测试用例 //String str = "1+2*3-4*5-6+7*8-9"; //123*+45*-6-78*+9- String str = "a*(b-c*d)+e-f/g*(h+i*j-k)"; // abcd*-*e+fg/hij*+k-*- //String str = "6*(5+(2+3)*8+3)"; //6523+8*+3+* //String str = "a+b*c+(d*e+f)*g"; //abc*+de*f+g*f Stack<Character> operators = new Stack<>(); //运算符 Stack output = new Stack(); //输出结果 rpn(operators, output, str); System.out.println(output); } public static void rpn(Stack<Character> operators, Stack output, String str) { char[] chars = str.toCharArray(); int pre = 0; boolean digital; //是否为数字(只要不是运算符,都是数字),用于截取字符串 int len = chars.length; int bracket = 0; // 左括号的数量 for (int i = 0; i < len; ) { pre = i; digital = Boolean.FALSE; //截取数字 while (i < len && !Operator.isOperator(chars[i])) { i++; digital = Boolean.TRUE; } if (digital) { output.push(str.substring(pre, i)); } else { char o = chars[i++]; //运算符 if (o == '(') { bracket++; } if (bracket > 0) { if (o == ')') { while (!operators.empty()) { char top = operators.pop(); if (top == '(') { break; } output.push(top); } bracket--; } else { //如果栈顶为 ( ,则直接添加,不顾其优先级 //如果之前有 ( ,但是 ( 不在栈顶,则需判断其优先级,如果优先级比栈顶的低,则依次出栈 while (!operators.empty() && operators.peek() != '(' && Operator.cmp(o, operators.peek()) <= 0) { output.push(operators.pop()); } operators.push(o); } } else { while (!operators.empty() && Operator.cmp(o, operators.peek()) <= 0) { output.push(operators.pop()); } operators.push(o); } } } //遍历结束,将运算符栈全部压入output while (!operators.empty()) { output.push(operators.pop()); } }}enum Operator { ADD('+', 1), SUBTRACT('-', 1), MULTIPLY('*', 2), DIVIDE('/', 2), LEFT_BRACKET('(', 3), RIGHT_BRACKET(')', 3); //括号优先级最高 char value; int priority; Operator(char value, int priority) { this.value = value; this.priority = priority; } /** * 比较两个符号的优先级 * * @param c1 * @param c2 * @return c1的优先级是否比c2的高,高则返回正数,等于返回0,小于返回负数 */ public static int cmp(char c1, char c2) { int p1 = 0; int p2 = 0; for (Operator o : Operator.values()) { if (o.value == c1) { p1 = o.priority; } if (o.value == c2) { p2 = o.priority; } } return p1 - p2; } /** * 枚举出来的才视为运算符,用于扩展 * * @param c * @return */ public static boolean isOperator(char c) { for (Operator o : Operator.values()) { if (o.value == c) { return true; } } return false; }}
源代码:
https://github.com/pingcai/Algorithm/tree/master/src/algorithm/ReversePolishNotation.java
参考
数据结构与算法分析-Java语言描述(P67)
https://zh.wikipedia.org/wiki/%E9%80%86%E6%B3%A2%E5%85%B0%E8%A1%A8%E7%A4%BA%E6%B3%95
- 【Algorithm】逆波兰表达式 Java实现
- 逆波兰表达式java实现
- 【Algorithm】算术表达式求值------逆波兰RPN
- 实现逆波兰表达式的java计算器
- 逆波兰表达式的java实现
- LeetCode 逆波兰表达式java实现
- Java实现-逆波兰表达式求值
- 逆波兰表达式实现
- java 逆波兰表达式
- 逆波兰表达式 java
- 逆波兰表达式 java
- 逆波兰表达式 ---java
- 逆波兰表达式算法实现
- 逆波兰表达式原理实现
- 波兰、逆波兰表达式
- Java求解逆波兰表达式
- java使用栈和逆波兰表达式实现四则运算
- Java实现逆波兰表达式(Evaluate Reverse Polish Notation)
- sshaboot
- SSM-8 登陆拦截器
- python中调用另一个文件下的.py程序
- 图像数据集制作
- Xilinx FPGA设计代码风格 以后逐渐补充
- 【Algorithm】逆波兰表达式 Java实现
- 【转】JVM调优总结(十二)-参考资料
- 同时安装vs2013与vs2101无法打开包括文件:“SDKDDKVer.h
- Leetcode 410. Split Array Largest Sum
- 时光机穿梭
- 2.swap-two-nodes-in-linked-list(交换链表中的两个结点)
- Grandpa's Estate
- React 入门实例教程
- 机器学习之numpy和matplotlib学习(三)