三种解析表达式
前缀表达式:操作符在操作数前面,是一种没有括号的算术表达式。
中缀表达式:操作符在操作数之间。
后缀表达式:操作符在操作数后面,是一种没有括号的算术表达式。
以3+4-5为例:
前缀表达式:+ 3 4 - 5
中缀表达式:3 + 4 - 5
后缀表达式:3 4 + 5 -
以(3+4)*5为例:
前缀表达式:+ 3 4 * 5
中缀表达式:(3 + 4) * 5
后缀表达式:3 4 + 5 *
以后缀表达式为例:
后缀表达式,指的是不包括括号,运算符放在两个运算对象的后面,所有的计算按预算符出现的顺序,严格从左向右进行(不再考虑运算符的优先规则)。
由于后缀表达式的运算符在两个操作数的后面,那么计算机在解析后缀表达式的时候,只需要从左向右扫描,也就是只需要向后扫描。
这样实现的逻辑就简单了,在计算机底层的硬件实现就要简单多了。
使用两个栈实现将中缀表达式转化为后缀表达式
如何将中缀表达式转化为后缀表达式:
1.初始化两个栈:运算符栈s1,中间结果栈s2
2.从左到右扫描表达式
3.遇到操作数压入s2
4.遇到运算符,比较其与s1栈顶运算符的优先级
(1)如果s1栈是空的,或者栈顶元素是“(”,或者运算符优先级比栈顶元素优先级高,就直接压入s1栈
(2)新的运算符优先级比s1栈顶元素低或者相等,就弹出s1栈顶的元素,压入s2栈,并从新判断该运算符(循环步骤4)
5.遇到括号
(1)遇到左括号(,直接压入s1栈
(2)遇到右括号),依次弹出s1栈顶元素,压入s2,直到遇到左括号为止,然后将这对括号丢掉
6.重复2-5,扫描完所有表达式
7.将s1剩余的运算符压入s2栈
package expression;
import java.util.Stack;
public class ExpressionTest1 {
public static void main(String[] args) {
String ex = "(34.6+56.2+58)*63-69";
midToRear(ex);
}
//实现整个中缀表达式向后缀表达式转换
public static void midToRear(String input){
//初始化两个栈,s1放运算符,s2放中间结果
Stack<Character> s1 = new Stack<>();
Stack<Object> s2 = new Stack<>();
//扫描表达式
int len = input.length();
char c;
char tmpChar;
String number;//临时存放操作数
int lastIndex = -1;
for (int i=0; i<len; i++){
c = input.charAt(i);
//遇到操作数
if(Character.isDigit(c)){//判断c是否是数字
lastIndex = getLastIndex(input,i);//获取操作数后面的运算符号对应在表达式中的索引值
number = input.substring(i,lastIndex);//左开右闭取值
i = lastIndex-1;
System.out.print(number+" ");
s2.push(number);
}
//遇到运算符
else if(isOperator(c)){
while (!s1.isEmpty() && s1.peek()!='(' && priorityCompare(c,s1.peek())<=0){
System.out.print(s1.peek() + " ");
s2.push(s1.pop());
}
s1.push(c);
}
//遇到括号
else if (c=='('){
s1.push(c);
}
else if (c == ')'){
while ((tmpChar=s1.pop())!='('){
System.out.print(tmpChar + " ");
s2.push(tmpChar);
}
}
//其他情况忽略
}
//将s1剩余的运算符压入s2栈
while (!s1.isEmpty()){
System.out.print(s1.peek()+" ");
s2.push(s1.pop());
}
}
//获取操作数后面的运算符号对应在表达式中的索引值
public static int getLastIndex(String input, int start){
int len = input.length();
char c;
int rs = -1;//我们规定-1为无效值
for (int i=start;i<len;i++){
c = input.charAt(i);
if(c == '.'){
continue;
}else if(!Character.isDigit(c)){
rs = i;
break;
}else if (i == len-1){
rs = len;
}
}
return rs;
}
//判断是否为运算符
public static boolean isOperator(char c){
return (c == '+' || c == '-' || c == '*' || c == '/');
}
//比较运算符优先级,op1<op2,返回-1;op1=op2,返回0;op1>op2,返回1
public static int priorityCompare(char op1,char op2){
if (op1 == '+' || op1 == '-'){
return (op2=='*' || op2=='/')?-1:0; //如果op2是*或/,返回-1,否则返回0
}
if (op2 == '+' || op2 == '-'){
return (op1=='*' || op1=='/')?1:0; //如果op2是*或/,返回-1,否则返回0
}
return 1; //默认返回1
}
}
升级版:计算出数值结果
package expression;
import java.util.Stack;
public class ExpressionTest1 {
public static void main(String[] args) {
String ex = "(1+2)/2-1";
System.out.println(midToRear(ex));
}
//实现整个中缀表达式向后缀表达式转换
public static Double midToRear(String input){
//初始化两个栈,s1放运算符,s2放中间结果
Stack<Character> s1 = new Stack<>();
Stack<Object> s2 = new Stack<>();
//扫描表达式
int len = input.length();
char c;
char tmpChar;
Double number;//临时存放操作数
int lastIndex = -1;
for (int i=0; i<len; i++){
c = input.charAt(i);
//遇到操作数
if(Character.isDigit(c)){//判断c是否是数字
lastIndex = getLastIndex(input,i);//获取操作数后面的运算符号对应在表达式中的索引值
number = Double.parseDouble(input.substring(i,lastIndex));//左开右闭取值
i = lastIndex-1;
System.out.print(number+" ");
s2.push(number);
}
//遇到运算符
else if(isOperator(c)){
while (!s1.isEmpty() && s1.peek()!='(' && priorityCompare(c,s1.peek())<=0){
System.out.print(s1.peek() + " ");
//s2.push(s1.pop());
//在这个循环里进行运算
//s2先pop两个,算完再push进去
double num2 = (double) s2.pop();
double num1 = (double) s2.pop();
s2.push(cal(num1,num2,s1.pop()));//实现计算
}
s1.push(c);
}
//遇到括号
else if (c=='('){
s1.push(c);
}
else if (c == ')'){
while ((tmpChar=s1.pop())!='('){
System.out.print(tmpChar + " ");
//s2先pop两个,算完再push进去
double num2 = (double) s2.pop();
double num1 = (double) s2.pop();
s2.push(cal(num1,num2,tmpChar));//实现计算
}
}
//其他情况忽略
}
//将s1剩余的运算符压入s2栈
while (!s1.isEmpty()){
System.out.print(s1.peek()+" ");
//s2先pop两个,算完再push进去
double num2 = (double) s2.pop();
double num1 = (double) s2.pop();
s2.push(cal(num1,num2,s1.pop()));//实现计算
}
System.out.println();
//返回最终结果
return (Double)s2.pop();
}
//获取操作数后面的运算符号对应在表达式中的索引值
public static int getLastIndex(String input, int start){
int len = input.length();
char c;
int rs = -1;//我们规定-1为无效值
for (int i=start;i<len;i++){
c = input.charAt(i);
if(c == '.'){
continue;
}else if(!Character.isDigit(c)){
rs = i;
break;
}else if (i == len-1){
rs = len;
}
}
return rs;
}
//判断是否为运算符
public static boolean isOperator(char c){
return (c == '+' || c == '-' || c == '*' || c == '/');
}
//比较运算符优先级,op1<op2,返回-1;op1=op2,返回0;op1>op2,返回1
public static int priorityCompare(char op1,char op2){
if (op1 == '+' || op1 == '-'){
return (op2=='*' || op2=='/')?-1:0; //如果op2是*或/,返回-1,否则返回0
}
if (op2 == '+' || op2 == '-'){
return (op1=='*' || op1=='/')?1:0; //如果op2是*或/,返回-1,否则返回0
}
return 1; //默认返回1
}
//实现计算操作
public static double cal(double num1, double num2, char op){//注意num1和num2的先后顺序
switch (op){
case '+':
return num1 + num2;
case '-':
return num1 - num2;
case '*':
return num1 * num2;
case '/':
if (num2==0) throw new IllegalArgumentException("除数不能为0");
return num1 / num2;
default:
return 0;
}
}
}
本文介绍如何使用两个栈将中缀表达式转化为后缀表达式的方法,并提供了一个具体的Java实现案例,同时展示了如何计算后缀表达式的数值结果。

2422

被折叠的 条评论
为什么被折叠?



