步骤主要是两部:
1.将算数表达式转换为后缀表达式
2.求后缀表达式的值
在之前首先要明确什么是后缀表达式:在我们写表达式时一般把操作符(+,-,,/)放在两个字符之间,例如A+B,A/B,这个被称为中缀表达式,而后缀表达式是将操作符放在字符后面,于是变成了AB+,AB/。如下表所示所示为典型的变换
首先解决第一个问题:如何将中缀表达式转化为后缀表达式?
首先解析3+45:
解析3*(4+5)
由上图可以看出,在读中缀表达式的时候既要向前读又要向后读,这样会比较麻烦,将中缀表达式转化为后缀表达式是一个不错的方法。
转化过程:
A+B-C
A+BC
A(B+C)
A+B*(C-D)
由上图可以看出将数据存在ABCD依次取出,将中间遇到的操作符暂时放入栈中,每当遇到优先级更高的操作符时则继续压栈,当下一个操作符优先级比栈顶的低时则出栈加入后缀表达式中。
package com.stackDemo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
public class LastSymbol {
static Stack<Character> sta = new Stack<>();
static String output="";
public static void main(String[] args) throws IOException {
String input,output;
input = getString();
output = mediumToLast(input);
System.out.println(output);
}
public static String mediumToLast(String input){
for(int i = 0; i < input.length(); i++){
char ch = input.charAt(i);
switch(ch){
case '-':
case '+':
doOper(ch,1);
break;
case '/':
case '*':
doOper(ch,2);
break;
case '(':
sta.push(ch);
break;
case ')':
gotParOper();
break;
default:output += ch;
break;
}
}
while(!sta.empty()){
output += sta.pop();
}
return output;
}
public static void doOper(char ch,int per){
int peri = 0;
while( !sta.isEmpty()){
if(ch == '(') {
sta.push(ch);
break;
}
char chp = sta.pop();
if(chp == '+' || chp == '-')peri = 1;
if(chp == '*' || chp == '/')peri = 2;
if(per <= peri)
output += chp;
else {
sta.push(chp);
break;
}
}
sta.push(ch);
}
public static void gotParOper(){
while(!sta.empty()){
char ch = sta.pop();
if(ch == '('){
break;
}
else{
output += ch;
}
}
}
public static String getString() throws IOException {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}
}
输入输出效果:
2,得到后缀表达式后,我们就需要求解了,求解方式如下所示:
全部退栈后得到的结果就是表达式结果。
package com.stackDemo;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Stack;
public class LastSymbol {
static Stack<Character> sta = new Stack<>();
static String output="";
public static void main(String[] args) throws IOException {
String input,output;
input = getString();
output = mediumToLast(input);
System.out.println(output);
Stack<Integer> lastsym = new Stack<>();
for(int i = 0; i < output.length(); i++){
char ch = output.charAt(i);
if(ch == '+' ||output.charAt(i) == '-' ||ch == '*' ||ch == '/' ){
int x = lastsym.pop();
int y = lastsym.pop();
if(ch == '+') y = y + x;
if(ch == '-') y -= x;
if(ch == '*') y = y*x;
if(ch == '/') y = y/x;
lastsym.push(y);
}else {
lastsym.push((int)output.charAt(i)-'0');
}
}
System.out.println(lastsym.pop());
}
public static String mediumToLast(String input){
for(int i = 0; i < input.length(); i++){
char ch = input.charAt(i);
switch(ch){
case '-':
case '+':
doOper(ch,1);
break;
case '/':
case '*':
doOper(ch,2);
break;
case '(':
sta.push(ch);
break;
case ')':
gotParOper();
break;
default:output += ch;
break;
}
}
while(!sta.empty()){
output += sta.pop();
}
return output;
}
public static void doOper(char ch,int per){
int peri = 0;
while( !sta.isEmpty()){
if(ch == '(') {
sta.push(ch);
break;
}
char chp = sta.pop();
if(chp == '+' || chp == '-')peri = 1;
if(chp == '*' || chp == '/')peri = 2;
if(per <= peri)
output += chp;
else {
sta.push(chp);
break;
}
}
sta.push(ch);
}
public static void gotParOper(){
while(!sta.empty()){
char ch = sta.pop();
if(ch == '('){
break;
}
else{
output += ch;
}
}
}
public static String getString() throws IOException {
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
String s = br.readLine();
return s;
}
}
如此,完成了最后的操作。
总结一下:充分利用了栈的后进先出的特点,一方面通过栈来保存操作符,完成中缀表达式转换成后缀表达式;另一方面,通过栈来暂存数值,每次遇到符号时取出两个值进行操作。