概念
- 前缀表达式又称波兰式,前缀表达式的运算符位于操作数之前。比如:
- × + 3 4 5 6
- 中缀表达式就是常见的运算表达式,如
(3+4)×5-6
- 后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后,比如:3 4 + 5 × 6 -
人类最熟悉的一种表达式1+2,(1+2)3,3+42+4等都是中缀表示法。对于人们来说,也是最直观的一种求值方式,先算括号里的,然后算乘除,最后算加减,但是,计算机处理中缀表达式却并不方便。
我们先看一个例子 (3+4)× 5 - 6
后缀表达式3 4 + 5 × 6 -
的计算
- 从左至右扫描,将3和4压入堆栈;
- 遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素,注意与前缀表达式做比较),计算出3+4的值,得7,再将7入栈;
- 将5入栈;
- 接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
- 将6入栈;
- 最后是-运算符,计算出35-6的值,即29,由此得出最终结果。
中缀表达式转换为后缀表达式
1.数字直接入队列
2.运算符要与栈顶元素比较
①栈为空直接入栈
②运算符优先级大于栈顶元素优先级则直接入栈
③小于或等于则出栈入列,再与栈顶元素进行比较,直到运算符优先级小于栈顶元
素优先级后,操作符再入栈
3.操作符是 (
则无条件入栈
4.操作符为 )
,则依次出栈入列,直到匹配到第一个“(”
为止,此操作符直接舍弃,“(”
直接出栈舍弃
public class SuffixAlgorithm {
private static char LEFT_BRACKET = Operator.LEFT_BRACKET.value;
private static char RIGHT_BRACKET = Operator.RIGHT_BRACKET.value;
private static void rpn(Stack<Character> operators, Stack output, String exp){
char[] chars = exp.toCharArray();
int len = chars.length;
int bracket = 0; // operators中的左括号的数量
for (int i = 0; i < len; ) {
int pre = i;//处理开始下标
boolean digital = Boolean.FALSE; //是否为数字(只要不是运算符,都是数字),用于截取字符串
while (i < len && !Operator.isOperator(chars[i])) {
i++;
digital = Boolean.TRUE;
}
if (digital) {//如果是数字,直接压入output
output.push(exp.substring(pre, i));
}else{
char o = chars[i++];
if (o == LEFT_BRACKET){//左括号直接压入output
operators.push(o);
bracket++;
continue;
}
if(o == RIGHT_BRACKET){//是右括号
if(bracket < 1){
throw new IllegalArgumentException("can't find '('");
}
//将operators栈顶弹出压入output直到左括号
while (!operators.empty()) {
char top = operators.pop();
if (top == LEFT_BRACKET) {
break;
}
output.push(top);
}
bracket--;
continue;
}
char p;
while (!operators.empty()
&& ( p = operators.peek()) != LEFT_BRACKET
&& Operator.cmp(o, p) <= 0){
output.push(operators.pop());
}
operators.push(o);
}
}
while (!operators.empty()){
output.push(operators.pop());
}
}
public static void main(String[] args) {
System.out.println(rpn("a*(b-c*d)+e-f/g*(h+i*j-k)"));
System.out.println("a,b,c,d,*,-,*,e,+,f,g,/,h,i,j,*,+,k,-,*,-");
}
public static String rpn(String exp){
Stack<Character> operators = new Stack<>();
Stack<Character> output = new Stack();
rpn(operators, output, exp);
String str = "";
for(int i=0; i<output.size();i++){
str += String.valueOf(output.get(i));
}
return str;
}
static 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;
}
public static Operator findOperator(char c){
for (Operator o : Operator.values()) {
if (o.value == c) {
return o;
}
}
return null;
}
}
}