下面所述方法支持整数的+、-、*、/、()操作
运行结果:
描述:
中缀表达式:通用的算术或逻辑公式表示方法,操作符是以中缀的形式处于操作数的中间,平时常用的算术表示方法。
后缀表达式: 后缀表达式是将操作符置于操作数的后面,如:3 4 +;后缀表达式的表达方式不唯一,如中缀表达式(a+b+c*d)/e,ab+cd*+e/与abcd*++e/都是其后缀表达式。
1.中缀表达式的合法性校验
分析:
将输入的表达式按操作符(+、-、*、/、左右括号)与数字(包括负数)以空格隔开,再将按照空格分隔后的字符串存入数组中,检验表达式合法分为两步,首先操作符不能在首位或者末位,其次操作符不能连续,括号必须匹配(遍历数组+栈检验),通过检验返回中缀表达式,没有通过检验返回null。
代码:
public static String check(String s){
if(s == null || s.length() == 0){
return null;
}
//1.添加空格
StringBuffer sb = new StringBuffer();
for(int i=0,len=s.length(); i<len; i++) {
char tmp = s.charAt(i);
if (tmp > '9' || tmp < '0') {//操作符
if(tmp == '-'&&(i==0 ||(i!=0 && s.charAt(i-1)=='('))){//负数的-号
int j=i;
i++;
while(i<len && '0'<=s.charAt(i) && s.charAt(i)<='9') {
i++;
}
sb.append(s.substring(j,i)).append(" ");
i--;
}else{
sb.append(String.valueOf(tmp)).append(" ") ;
}
}else{
int j=i;
while(i<len && '0'<=s.charAt(i) && s.charAt(i)<='9') {
i++;
}
sb.append(s.substring(j,i)).append(" ");
i--;
}
}
String[] str = sb.toString().split(" ");
//2.检验中缀表达式是否合法
//2.1操作符"+","-","*","/"不能出现在首位,末位
if("+".equals(str[0]) || "-".equals(str[0]) ||"*".equals(str[0]) ||"/".equals(str[0]) ||
"+".equals(str[str.length-1]) || "-".equals(str[str.length-1])
||"*".equals(str[str.length-1]) ||"/".equals(str[str.length-1]) ){
return null;
}
//2.2操作符"+","-","*","/"“不能连续,括号成对匹配
Stack<String> stack = new Stack<>();
for(int i=0; i<str.length; i++){
if("(".equals(str[i])){//左括号入栈
stack.push(str[i]);
}else if(")".equals(str[i])){//右括号出栈
if(!("(".equals(stack.pop()))){
return null;
}
}else if(("+".equals(str[i]) || "-".equals(str[i]) ||"*".equals(str[i]) ||"/".equals(str[i]))
&& ("+".equals(str[i-1]) || "-".equals(str[i-1]) ||"*".equals(str[i-1]) ||"/".equals(str[i-1]))){//连续操作符
return null;
}
}
return stack.empty() ? sb.toString() : null;//栈不为空说明括号不匹配
}
测试:
2.中缀表达式转后缀表达式
分析:
创建两个栈:stack1存操作符,stack2存数字(也存一些计算结果),将传入的中缀表达式以空格分隔存入数组str,遍历数组
情况一:如果是+、-、*、/、( 操作符,放入stack1中,
情况二:如果是数字,放入stack2中,判断stack1的栈顶是否是*或/,是则在stack2中弹出两个数字,在stack1中弹出一个操作符,将数字1+" " +数字2+" " +操作符(这相当于局部的一个结果)存入stack2中,执行上述操作直到stack1的栈顶不为*或/。
情况三:如果是 ),在stack2中弹出两个数字,在stack1中弹出一个操作符,将数字1+" " +数字2+" " +操作符 存入stack2中,执行上述操作直到stack1的栈顶弹出( ,此时相当于计算完了一对括号中的表达式,结果存在stack2的栈顶,这时还要判断stack1的栈顶是否是*或/,是的话就满足情况二,进行情况二的操作。
遍历完毕,stack1中只剩了+、-两种操作符,将stack1和stack2的内容逆置,这样就符合+、-操作的顺序了,于是在两个栈中又进行弹出操作符和数字的操作,直到stack1为空,stack2存的就是最终的后缀表达式。
以-2 * ( 1 - 2 ) + 6 / 3进行演示:
代码:
public static String intoSuffix(String infix){
Stack<String> stack1 = new Stack<>();//放操作符的栈
Stack<String> stack2 = new Stack<>();//放数字的栈
String[] str = infix.split(" ");
for(int i=0,len = str.length; i<len; i++){
String tmp = str[i];
if(")".equals(str[i])) {
String mark = stack1.pop();//弹出操作符
while ((!"(".equals(mark)) && (!stack1.empty())) {
//弹出两个数字
String number2 = stack2.pop();
String number1 = stack2.pop();
String result = number1 + " " + number2 + " " + mark;//结果
stack2.push(result);//结果入栈
mark = stack1.pop();//更新操作符
}
while(!stack1.empty() && ("*".equals(stack1.peek()) ||"/".equals(stack1.peek()))){
//弹出两个数字
String number2 = stack2.pop();
String number1 = stack2.pop();
String mark1 = stack1.pop();
String result = number1 + " " + number2 + " " + mark1;//结果
stack2.push(result);//结果入栈
}
}else if("+".equals(str[i]) || "-".equals(str[i]) ||
"*".equals(str[i]) ||"/".equals(str[i])||"(".equals(str[i])){//操作符
stack1.push(tmp);
}
else{//数字
stack2.push(str[i]);
while(!stack1.empty() && ("*".equals(stack1.peek()) ||"/".equals(stack1.peek()))){
//弹出两个数字
String number2 = stack2.pop();
String number1 = stack2.pop();
String mark1 = stack1.pop();
String result = number1 + " " + number2 + " " + mark1;//结果
stack2.push(result);//结果入栈
}
}
}
Stack<String> stack11 = new Stack<>();//放操作符
Stack<String> stack22 = new Stack<>();//放数字
while(!stack1.empty()){
stack11.push(stack1.pop());
}
while(!stack2.empty()){
stack22.push(stack2.pop());
}
while(!stack11.empty()){
String mark = stack11.pop();//弹出操作符
String number1 = stack22.pop();//弹出两个数字
String number2 = stack22.pop();
String result = number1+" "+number2+" "+mark;//结果
stack22.push(result);//结果入栈
}
return stack22.pop();
}
3.后缀表达式的计算
分析:
以空格分隔后缀表达式,结果存入数组str中,创建栈stack,遍历数组,遇到数字压栈,遇到操作符(+、-、*、/)在栈中弹出两个数字,计算出结果,如操作符是+,就计算数字1+数字2,将计算结果压栈,遍历完毕返回栈顶的结果。
以-2 1 2 - * 6 3 / +进行演示:
代码:
public static int calculateSuffix(String suffix){
String[] s = suffix.split(" ");
Stack<Integer> stack = new Stack<>();
for(int i=0; i<s.length; i++){
if(("+".equals(s[i])) || ("-".equals(s[i])) || ("*".equals(s[i])) || ("/".equals(s[i]))){//操作符
int number2 = stack.pop();
int number1 = stack.pop();
int result = 0;
if("+".equals(s[i])){
result = number1+number2;
}else if("-".equals(s[i])){
result = number1-number2;
}else if("*".equals(s[i])){
result = number1*number2;
}else if("/".equals(s[i])){
result = number1/number2;
}
stack.push(result);
}else{//数字
stack.push(Integer.parseInt(s[i]));
}
}
return stack.pop();
}
主函数:
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String str= sc.nextLine();
System.out.print("中缀表达式:");
String infix = check(str);
if(infix == null){
System.out.println("表达式不合法");
}else{
System.out.println(infix);
String suffix = intoSuffix(infix);
System.out.println("后缀表达式:"+suffix);
System.out.println("计算结果:"+calculateSuffix(suffix));
}
}