一. 后缀表达式求值
后缀表达式也叫逆波兰表达式,其求值过程可以用到栈来辅助存储。假定待求值的后缀表达式为:6 5 2 3 + 8 * + 3 + *,则其求值过程如下:
-
1)遍历表达式,遇到的数字首先放入栈中,此时栈如下所示:
-
2)接着读到“+”,则弹出3和2,执行3+2,计算结果等于5,并将5压入到栈中。
-
3)读到8,将其直接放入栈中。
-
4)读到“”,弹出8和5,执行85,并将结果40压入栈中。而后过程类似,读到“+”,将40和5弹出,将40+5的结果45压入栈…以此类推。最后求的值288。
java实现代码,有点臃肿
import java.util.Stack;
public class Test150_demo_1 {
//放入的是数字不变,放入的是操作符,拿出栈顶下的第二个数,和第一个数操作完毕,在放入栈中
public static int evalRPN(String[] tokens) {
Stack<Integer> s = new Stack<Integer>();
for(int i=0;i<tokens.length;i++){
if(isstr(tokens[i])){ //是字符
int num1 = s.pop();
int num2 = s.pop();
int result = 0;
if(tokens[i].equals("+")){
result = num2+num1;
}
if(tokens[i].equals("-")){
result = num2-num1;
}
if(tokens[i].equals("*")){
result = num2*num1;
}
if(tokens[i].equals("/")){
result = num2/num1;
}
s.push(result);
}
else if(!isstr(tokens[i])){ //是数字
s.push(Integer.parseInt(tokens[i]));
}
}
return s.pop();
}
private static boolean isstr(String tokens) {
if(tokens=="+"||tokens=="-"||tokens=="*"||tokens=="/"){
return true;
}
return false;
}
}
二.中缀表达式求值
后缀表达式也叫波兰表达式,而计算机不认识中缀表达式,需要转成后缀表达式进行求值。
中缀表达式转后缀表达式转化规则如下:
中缀表达式a + b*c + (d * e + f) * g,其转换成后缀表达式则为a b c * + d e * f + g * +。
转换过程需要用到栈,具体过程如下:
首先规定优先级
( >* = / > + = -
左括号>乘=除>+
只有右括号入栈后才把左括号到右括号之间的内容弹出
-
1)如果遇到操作数,我们就直接将其输出。
-
2)如果遇到操作符,则我们将其放入到栈中,遇到左括号时我们也将其放入栈中。
-
3)如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
-
4)如果遇到任何其他的操作符,如(“+”, “*”,"( ”)等,从栈中弹出元素直到遇到发现更低优先级的元素(或者栈为空)为止。弹出完这些元素后,才将遇到的操作符压入到栈中。有一点需要注意,只有在遇到" ) “的情况下我们才弹出” ( “,其他情况我们都不会弹出” ( "。
-
放入的操作符和栈顶元素比较优先级 如果优先级大 放入,如果优先级小于栈顶元素,弹出栈顶元素,拿现在的栈顶元素相比,直到放入操作符的优先级大于栈顶元素的优先级,否则,弹出栈顶元素
-
5)如果我们读到了输入的末尾,则将栈中所有元素依次弹出。
public class 中缀表达式转后缀表达式 {
public static HashMap<String, Integer> map = new HashMap<String, Integer>();
public static StringBuffer sb = new StringBuffer();
public static String transform(String strs[]){
Stack<String> s = new Stack<String>();
for(String str : strs){
System.out.println(str);
if(!isstr(str)){
if(str.equals("(")) s.push(str);
else sb.append(str);
}
else if(isstr(str)){ //如果是运算符号
if(str.equals(")")){
while(!s.peek().equals("(")){
sb.append(s.pop());
}
s.pop();//弹出(
}
else{ //如果是加减乘除等操作符号 看优先级
boolean isntInsert = true;
if(s.size()==0) {
s.push(str);
isntInsert = false; //插入成功
}
while(isntInsert&&s.size()>0){
if((map.get(str)>map.get(s.peek())||map.get(s.peek()).equals("("))){ //如果要放的优先级大于栈顶的优先级
s.push(str);
isntInsert = false;
}
else{ //如果优先级小与等于
sb.append(s.pop());
}
}
if(s.size()==0) s.push(str); //如果退不了 了
}
}
}
while(!s.isEmpty()){
sb.append(s.pop());
}
return sb.toString();
}
public static boolean isstr(String tokens) {
if(tokens.equals("+")||tokens.equals("-")||tokens.equals("*")||tokens.equals("/")||tokens.equals(")")){
return true;
}
return false;
}
public static void main(String[] args) {
/*
* 主要逻辑 :
* 1 . 数字直接放入
* 2 . 操作符判断与栈顶的优先级关系,优先级大,放入。 优先级小于栈顶,弹出栈顶元素
* 3 . 如果遇到一个右括号,则将栈元素弹出,将弹出的操作符输出直到遇到左括号为止。注意,左括号只弹出并不输出。
* 4 . 如果我们读到了输入的末尾,则将栈中所有元素依次弹出。
*/
map.put("c", Integer.MAX_VALUE);
map.put("+", 1);
map.put("-", 1);
map.put("*", 2);
map.put("/", 2);
map.put("(", 0);
String s [] = {"3","+","5","*","(", "2" ,"+","6","-", "1" ,")"};
System.out.println(transform(s));
}
}
接下来我们就可以用后缀表达式,尽情的玩耍啦