在后面要注意区别 :前缀和后缀表达式的运算中栈顶元素和次栈顶元素,计算时的前后位置。
从右至左扫描表达式,遇到数字时,将数字压入栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素和次栈顶元素),并将结果入栈;重复上述过程直到表达式的最左端,最后运算得出的值即为表达式的结果。
例如:(1+2)*3-4对应的前缀表达式就是 - * + 1 2 3 4,求值步骤如下:
注意点:给出的波兰表达式要用空格隔开,并且表达式正确,支持多位数
public class Poland {
public static void main(String[] args) {
//给出波兰表达式
String Expression="- * + 1 2 3 4";
List<String> LISTNUM=getList(Expression);
System.out.println(LISTNUM);
int result=Calculate(LISTNUM);
System.out.println("波兰表达式的结果为:"+result);
}
/**
* 将波兰表达式发到list集合中
* @return
*/
public static List<String> getList(String Expression){
String[] split=Expression.split(" "); //用空格分割
List<String> list=new ArrayList<String>();
//循环
for(String item : split) {
list.add(item);
}
return list;
}
/**
* 求值
* @param list
* @return
*/
public static int Calculate(List<String> list) {
//建栈
Stack<String> stack=new Stack<String>();
for(int i=list.size()-1;i>=0;i--) {
String ele=list.get(i);
//这里使用正则表达式,匹配的是多位数
if(ele.matches("\\d+")) {
//入栈
stack.push(ele);
}else {
//先pop两个数进行计算,在入栈【这里是先pop出来的数与后pop出来的数运算】
int num1=Integer.parseInt(stack.pop());
int num2=Integer.parseInt(stack.pop());
System.out.println("num1="+num1+" 和 num2="+num2+"进行"+ele+"运算");
int res=0;
if(ele.equals("+")) {
res=num1+num2;
}else if(ele.equals("-")) {
res=num1-num2;
}else if(ele.equals("*")) {
res=num1*num2;
}else if(ele.equals("/")) {
res=num1/num2;
}else {
throw new RuntimeException("波兰表达式出现了问题!!!");
}
//入栈
stack.push(""+res);
}
}
//最后留在栈中的是运算结果
return Integer.parseInt(stack.pop());
}
}
初始化两个栈:运算符栈s1和存储中间结果栈s2;
从右到左扫描中缀表达式;
遇到操作数时,将其压入s2;
遇到运算符时,比较其与s1栈顶运算符的优先级;
(4-1)如果s1为空,或者栈顶运算符为右括号 “ ) ”,则直接将此运算符入栈;
(4-2)否则,若优先级比栈顶运算符的高或者相等,也将运算符压入s1;
(4-3)否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
遇到括号时:
(5-1)如果是右括号 “ ) ”,则直接压入s1;
(5-2)如果是左括号" ( ",则依次弹出s1中栈顶的运算符压入s2,直到遇到右括号为止,此时将这一对括号丢弃;
重复步骤2至5,直到表达式的最左边;
将s1中剩余的运算符依次弹出并压入到s2中;
依次弹出s2中的元素并输出,结果即为中缀表达式对应的前缀表达式。
举例: 1+((2+3) x 4)-5转前缀表达式
扫描到的元素 | s1(栈底=>栈顶) | s2(栈底=>栈顶) | 说明 |
---|---|---|---|
5 | 空 | 5 | 数字,直接入栈 |
- | - | 5 | s1为空,运算符直接入栈 |
) | - ) | 5 | 右括号,直接入栈 |
4 | - ) | 5,4 | 数字,直接入栈 |
x | - ) x | 5,4 | s1栈顶为右括号,直接入栈 |
) | - ) x ) | 5,4 | 右括号,直接入栈 |
3 | - ) x ) | 5,4,3 | 数字,直接入栈 |
+ | - ) x ) + | 5,4,3 | s1栈顶为右括号,直接入栈 |
2 | - ) x ) + | 5,4,3,2 | 数字,直接入栈 |
( | - ) x | 5,4,3,2,+ | 左括号,弹出s1中栈顶的运算符压入s2,直到遇到右括号为止,此时将这一对括号丢弃 |
( | - | 5,4,3,2,+,x | 左括号,弹出s1中栈顶的运算符压入s2,直到遇到右括号为止,此时将这一对括号丢弃 |
+ | - + | 5,4,3,2,+,x | -与+优先级相同,压入+到s1 |
1 | - + | 5,4,3,2,+,x ,1 | 数字,直接入栈 |
到达最左端 | 空 | 5,4,3,2,+,x ,1,+,- | 将s1中剩余的运算符依次弹出并压入到s2中 |
public class MidToBefore {
public static void main(String[] args) {
//中缀表达式
String Expression="1+((2+3)*4)-5";
List<String> LISTNUM=MidToList(Expression);
System.out.println("中缀表达式的list=>"+LISTNUM);
List<String> ls=ToBeforeList(LISTNUM);
Collections.reverse(ls); //逆序
System.out.println("前缀表达式的list=>"+ls);
}
/**
* 将中缀list=>前缀list
* @param list
* @return
*/
public static List<String> ToBeforeList(List<String> list){
//定义一个栈
Stack<String> s1=new Stack<String>(); //符号栈
//定义一个集合替代存储中间结果的栈s2
List<String> s2=new ArrayList<String>();
//遍历list,从右到左
for (int i=list.size()-1;i>=0;i--) {
//如果是一个数,直接入栈,正则判断
if(list.get(i).matches("\\d+")) {
s2.add(list.get(i));
//如果是右括号,直接压入s1
}else if(list.get(i).equals(")")){
s1.push(list.get(i));
//如果是左括号
}else if(list.get(i).equals("(")) {
//如果是左括号,则依次弹出s1的栈顶运算符,并压入s2中,直到遇到右括号,然后将这个括号丢弃
while(!s1.peek().equals(")")) {
s2.add(s1.pop());
}
s1.pop(); //消除小括号
}else {
//当遍历出来的元素 的优先级小于s1栈顶运算符,将s1栈顶的运算符弹出并加入到s2中,再次与新的s1栈顶运算符相比较
while(s1.size()!=0 && Operation1.getPro(list.get(i))<Operation1.getPro(s1.peek())) {
s2.add(s1.pop());
}
//还需将遍历出来的元素 压入栈
s1.push(list.get(i));
}
}
//将s1中剩余的符号依次弹出,压入到s2中
while(s1.size()!=0) {
s2.add(s1.pop());
}
return s2;//遍历出来就是前缀表达式的逆序
}
/**
* 将中缀表达式转成对应的list
* @param s
* @return
*/
public static List<String> MidToList(String s){
//定义一个list,存放中缀表达式 对应的内容
List<String> list=new ArrayList<String>();
int index=0; //作为一个扫描的指针
String str; //用于多位数的拼接
char c; //每一次扫到的字符
do {
//如果c是一个非数字,就加入到list中
//Char("48")==>0 Char("57")==>9
if((c=s.charAt(index))<48 ||(c=s.charAt(index))>57) {
list.add(""+c);
index++; //扫描指针后移
}else {//如果是一个数字
str=""; //先将str设置为""
while(index<s.length() && (c=s.charAt(index))>=48 &&(c=s.charAt(index))<=57) {
str+=c; //拼接
index++;
}
list.add(str);
}
}while(index<s.length());
return list;
}
}
//编写一个类,可以返回一个运算符对应的优先级
class Operation1{
private static int LK=0; //在栈顶为(时,依然用出来比较
private static int RK=0;
private static int ADD=1;
private static int SUB=1;
private static int MUL=2;
private static int DIV=2;
//写一个方法,返回一个对应的优先级
public static int getPro(String key) {
int result=0;
switch (key) {
case "(":
result=LK;
break;
case ")":
result=RK;
break;
case "+":
result=ADD;
break;
case "-":
result=SUB;
break;
case "*":
result=MUL;
break;
case "/":
result=DIV;
break;
default:
System.out.println("不支持"+key+"运算符!");
break;
}
return result;
}
}
注意点:给出的逆波兰表达式要用空格隔开,并且表达式正确,支持多位数
public class PolandDemo {
public static void main(String[] args) {
//逆波兰表达式
String Expression="1 2 + 3 * 4 -";
List<String> LISTNUM=getList(Expression);
System.out.println(LISTNUM);
int result=Calculate(LISTNUM);
System.out.println("逆波兰表达式的结果为:"+result);
}
/**
* 将逆波兰表达式发到list集合中
* @return
*/
public static List<String> getList(String Expression){
String[] split=Expression.split(" ");
List<String> list=new ArrayList<String>();
//循环
for(String item : split) {
list.add(item);
}
return list;
}
/**
* 求值
* @param list
* @return
*/
public static int Calculate(List<String> list) {
//建栈
Stack<String> stack=new Stack<String>();
for(String ele : list) {
//这里使用正则表达式,匹配的是多位数
if(ele.matches("\\d+")) {
//入栈
stack.push(ele);
}else {
//先pop两个数进行计算,在入栈【这里是后pop出来的数与先pop出来的数运算】
int num2=Integer.parseInt(stack.pop());
int num1=Integer.parseInt(stack.pop());
System.out.println("num1="+num1+"\t和num2="+num2+"进行"+ele+"运算");
int res=0;
if(ele.equals("+")) {
res=num1+num2;
}else if(ele.equals("-")) {
res=num1-num2;
}else if(ele.equals("*")) {
res=num1*num2;
}else if(ele.equals("/")) {
res=num1/num2;
}else {
throw new RuntimeException("逆波兰表达式出现了问题!!!");
}
//入栈
stack.push(""+res);
}
}
//最后留在栈中的是运算结果
return Integer.parseInt(stack.pop());
}
}
初始化两个栈:运算符栈s1和存储中间结果栈s2;
从左到右扫描中缀表达式;
遇到操作数时,将其压入s2;
遇到运算符时,比较其与s1栈顶运算符的优先级;
(4-1)如果s1为空,或者栈顶运算符为左括号 “ ( ”,则直接将此运算符入栈;
(4-2)否则,若优先级比栈顶运算符的高,也将运算符压入s1;
(4-3)否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
遇到括号时:
(5-1)如果是左括号 “ ( ”,则直接压入s1;
(5-2)如果是右括号" ) ",则依次弹出s1中栈顶的运算符压入s2,直到遇到左括号为止,此时将这一对括号丢弃;
重复步骤2至5,直到表达式的最右边;
将s1中剩余的运算符依次弹出并压入到s2中;
依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式。
举例: 1+((2+3) x 4)-5转后缀表达式
扫描到的元素 | s1(栈底=>栈顶) | s2(栈底=>栈顶) | 说明 |
---|---|---|---|
1 | 空 | 1 | 数字,直接入栈 |
+ | + | 1 | s1为空,运算符直接入栈 |
( | + ( | 1 | 左括号,直接入栈 |
( | +(( | 1 | 同上 |
2 | +(( | 1,2 | 数字,直接入栈 |
+ | +(( + | 1,2 | s1栈顶为左括号,直接入栈 |
3 | +(( + | 1,2,3 | 数字,直接入栈 |
) | +( | 1,2,3,+ | 右括号,弹出s1中栈顶的运算符压入s2,直到遇到左括号为止,此时将这一对括号丢弃 |
x | +( x | 1,2,3,+ | s1栈顶为左括号,直接入栈 |
4 | +( x | 1,2,3,+ ,4 | 数字,直接入栈 |
) | + | 1,2,3,+ ,4,x | 右括号,弹出s1中栈顶的运算符压入s2,直到遇到左括号为止,此时将这一对括号丢弃 |
- | - | 1,2,3,+ ,4,x,+ | -与+优先级相同,因此弹出+,再压入- |
5 | - | 1,2,3,+ ,4,x,+ ,5 | 数字,直接入栈 |
到达最右端 | 空 | 1,2,3,+ ,4,x,+ ,5 ,- | s1中剩余的运算符 |
public class MidToAfter {
public static void main(String[] args) {
//中缀表达式
String Expression="1+((2+3)*4)-5";
List<String> LISTNUM=MidToList(Expression);
System.out.println("中缀表达式的list=>"+LISTNUM);
List<String> ls=ToAfterList(LISTNUM);
System.out.println("后缀表达式的list=>"+ls);
}
/**
* 将中缀list=>后缀list
* @param list
* @return
*/
public static List<String> ToAfterList(List<String> list){
//定义一个栈
Stack<String> s1=new Stack<String>(); //符号栈
//定义一个集合替代存储中间结果的栈s2
List<String> s2=new ArrayList<String>();
//遍历list
for (String item : list) {
//如果是一个数,直接入栈
if(item.matches("\\d+")) {
s2.add(item);
}else if(item.equals("(")){
s1.push(item);
}else if(item.equals(")")) {
//如果是右括号,则依次弹出s1的栈顶运算符,并压入s2中,直到遇到左括号,然后将这个括号丢弃
while(!s1.peek().equals("(")) {
s2.add(s1.pop());
}
s1.pop(); //消除小括号
}else {
//当item的优先级小于或者等于s1栈顶运算符,将s1栈顶的运算符弹出并加入到s2中,再次与新的s1栈顶运算符
while(s1.size()!=0 && Operation.getPro(item)<=Operation.getPro(s1.peek())) {
s2.add(s1.pop());
}
//还需将item压入栈
s1.push(item);
}
}
//将s1中剩余的符号依次弹出,压入到s2中
while(s1.size()!=0) {
s2.add(s1.pop());
}
return s2;//因为存放再list中,遍历出来就是后缀表达式
}
/**
* 将中缀表达式转成对应的list
* @param s
* @return
*/
public static List<String> MidToList(String s){
//定义一个list,存放中缀表达式 对应的内容
List<String> list=new ArrayList<String>();
int index=0; //作为一个扫描的指针
String str; //用于多位数的拼接
char c; //每一次扫到的字符
do {
//如果c是一个非数字,就加入到list中
//Char("48")==>0 Char("57")==>9
if((c=s.charAt(index))<48 ||(c=s.charAt(index))>57) {
list.add(""+c);
index++; //扫描指针后移
}else {//如果是一个数字
str=""; //先将str设置为""
while(index<s.length() && (c=s.charAt(index))>=48 &&(c=s.charAt(index))<=57) {
str+=c; //拼接
index++;
}
list.add(str);
}
}while(index<s.length());
return list;
}
}
//编写一个类,可以返回一个运算符对应的优先级
class Operation{
private static int LK=0; //在栈顶为(时,依然用出来比较
private static int RK=0;
private static int ADD=1;
private static int SUB=1;
private static int MUL=2;
private static int DIV=2;
//写一个方法,返回一个对应的优先级
public static int getPro(String key) {
int result=0;
switch (key) {
case "(":
result=LK;
break;
case ")":
result=RK;
break;
case "+":
result=ADD;
break;
case "-":
result=SUB;
break;
case "*":
result=MUL;
break;
case "/":
result=DIV;
break;
default:
System.out.println("不支持"+key+"运算符!");
break;
}
return result;
}
}
最后,如果想要使用中缀表达式转后缀表达式进行运算,可以将转换好的后缀表达式进行拼接成字符串,然后调用先前 1.4.2 代码实现
String str="";
for(String item:ls) {
str+=item.concat(" ");
}
System.out.println(str);