中缀表达式转前缀、后缀表达式(支持多位数字、小数的运算)

1.几种表达式的了解

1.1中缀表达式

1.1.1 定义

所谓的中缀表达式,就是我们平常见到式子,比如 ( 3 + 4 ) * 5 - 6

1.1.2 计算

中缀表达式的计算,通常是转换成后缀表达式进行计算

1.2前缀表达式

1.2.1 定义

前缀表达式又叫做波兰表达式,操作运算符位于数字前面

1.2.2 计算

前缀表达式的计算:新建一个,然后对表达式从右到左进行遍历,如果遇到数字,那么将数字压入栈中,如果遇到的是操作运算符,那么就从栈中跳出两个数字num1,num2,并进行相应的运算,此时需要注意相关的运算法则,比如除法中的除数不可以为0,然后将结果再次压入到栈中。注意如果是 - 号、/ 号 , % 号,那么必须是num1 - num2,num1 / num2,num1 % num2,而+号,*号就不用区分,因为结果都一样的嘛,为什么会这样子呢?请看图解。
在这里插入图片描述

遍历结束之后,栈中只剩下一个元素,那么这个元素就是表达式的值,将其从栈中跳出即可。

1.3后缀表达式

1.3.1 定义

后缀表达式又叫做逆波兰表达式,操作运算符位于数字之后。比如(3 + 4 ) * 5 - 6 的后缀表达式为 3 4 + 5 * 6 - 。

几种常见的中缀表达式对应的后缀表达式
在这里插入图片描述在这里插入图片描述

1.3.2 计算

后缀表达式的计算:新建一个,然后对表达式从左到右进行遍历,刚好和前缀表达式相反,如果遇到数字,那么将数字压入栈中,如果遇到的是操作运算符,那么就从栈中跳出两个数字num1,num2,并进行相应的运算,此时需要注意相关的运算法则,比如除法中的除数不可以为0,然后将结果再次压入到栈中。注意如果是 - 号、/ 号 , % 号,那么必须是num2 - num1,num2 / num1,num2 % num1,而+号,*号就不用区分,因为结果都一样的嘛,为什么会这样子呢?请看图解。

在这里插入图片描述
遍历结束之后,栈中只剩下一个元素,那么这个元素就是表达式的值,将其从栈中跳出即可。

2.中缀表达式转前缀、后缀表达式,并计算其值

中缀表达式转换其他两种表达式都需要用到

2.1 中缀表达式转后缀表达式

2.1.1 思路

我的思路是通过两个栈来实现的,如果有更好的方法,还请指教。
过程:
1)从左到右遍历表达式
2)如果遇到数字,那么就要将其压入到栈array中。不过需要注意多位数字的问题。
3)如果遇到的是字符,那么将分几种情况来讨论:
①如果存放字符的栈stringArray为空,或者栈顶的符号是左括号,或者当前的符号是左括号,那么直接将当前符号压入栈stringArray
②否则,如果当前符号是右括号,那么需要通过循环来找到左括号,找到左括号之后将其跳出栈,从而消除括号。注意在每一次循环中, 需要括号内的符号压入到栈array中。
③如果都不符合上面的情况,那么要将当前符号和栈顶符号比较优先级。如果当前符号的优先级大于栈顶符号的优先级,那么直接将当前符号压入栈stringArray中,否则,不断将stringArray的栈顶符号跳出,然后将其压入到栈array中,直到当前符号的优先级大于栈顶符号的优先级,才可以将当前符号压入栈stringArray中。
4)将array中的所有元素都压入到栈arrayString中
在这里插入图片描述

由图可以知道,将array中的元素压入到arrayString中,遍历arrayString得到的才是后缀表达式,否则,如果将arrayString的元素压入到array,遍历array,得到的是后缀表达式的倒序,此时还需要将其转换过来,就显得玛法些。
5)遍历arrayString,将arrayString的元素赋给
字符串列表List,得到的字符串列表就是是后缀表达式

可能有同学会问,可以是字符串数组吗我认为是不可以的如果定义的字符串数组的长度是原来表达式的长度,可能会报错,因为有括号()的存在,即使没有括号,还要考虑多位数字的存在,从而影响了前缀表达式的长度不再是原来中缀表达式的长度了。还有人会想,那么我定义字符串数组长度很大不就行了,感觉上是可以的,但是会占据比较大的空间,而且进行运算的时候,也会比较麻烦,因为要统计实际上数组中字符的个数,所以综合来说,我觉得还是用列表好一些,这只是我的个人见解,如果有什么不对的地方,请指正。

2.1.2 代码实现:

这个代码可以实现多位数字的运算,但是不可以实现小数的,因为进行计算的时候是整形,返回的也是整形,如果有小数,就没有办法得到正确结果。
需要补充的地方是我这里字符串的输入格式一定是3 + 5 * 6 - 1,每一个字符间用一个空格隔开,因为主函数那里通过方法split(),将字符串分割成字符串,这样就不需要在定义一个变量用于拼接多位数字了

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class SuffixExpressionTest {
       public Stack<String> array;
       public Stack<String> stringArray; 
       public int length ;
       /**
        * 新建两个栈
        * @param infixExpression
        */
       public SuffixExpressionTest(String[] infixExpression) {
    	   array = new Stack<String>();
    	   stringArray = new Stack<String>();
    	   length = infixExpression.length;
       }   
       public List<String> getSuffixExpression(String[] infixExpression) {
    	   if(infixExpression == null)
    		   throw new RuntimeException("字符串为空, 请输入字符串");
    	   List<String> string = new ArrayList<String>();
    	   //从左到右开始遍历字符串
    	   for(int i = 0; i<length; i++) {
    		   String ch = infixExpression[i];//获得下标为i的字符串
    		   //判断是否为基本运算符
    		   if(isOper(ch)) {
    			   //如果是基本运算符,那么分情况讨论
    			   if(stringArray.empty() || stringArray.peek().equals("(")) {
    				   //如果栈为空, 或者栈顶是左括号,直接入栈
    				   stringArray.push(ch);
    			   }else if(ch.equals("(")) {
    				   //如果当前符号是左括号,那么直接入栈
    				   stringArray.push(ch);
    			   }else if(ch.equals(")")) {
    				   //如果当前符号是右括号,那么就将从栈S1中跳出2个数字,然后栈S2中跳出一个符号,进行相应的运算,将结果压入栈S1
    				   //重复上述操作,直到遇到左括号
    				   while(!stringArray.peek().equals("(")) {
    					   String temp = stringArray.pop();
    					   array.push(temp);
    				   }
    				   stringArray.pop();//将左括号从栈中跳出,消除左括号
    			   }else {
    				   //如果当前符号都不符合上面的几种情况,那么比较优先级
    				   int level_current = priority(ch);
    				   int level_peek = priority(stringArray.peek());
    				   if(level_current  > level_peek) {
    					   stringArray.push(ch);//如果当前符号的优先级大于栈顶的优先级,那么直接将符号压入栈中
    				   }else {
    				   /*
    				   如果当前符号的优先级小于等于栈顶符号的优先级,那么
    				   将栈顶符号跳出,然后将这个跳出的栈顶符号压入到
    				   array栈中,重复上述操作,直到栈顶符号的优先级小于
    				   当前符号的优先级或者栈为空的时候,才将当前符号压入
    				   到stringArray栈中
    				   */
    				       while(level_current <= level_peek){
                                 String temp = stringArray.pop();
    					         array.push(temp);
    					         if(stringArray.empty())
    					            break;//如果stringArray栈为空,那么退出循环
    					         level_peek = priority(stringArray.peek());
                            }
    					   
    					   stringArray.push(ch);//当前符号压入栈S2
    				   }
    			   }
    		   }else {
    			   array.push(ch);
    		   }
    	   }
    	   //结束遍历之后,判断S2是否为空,如果不为空,就将其所有元素压入栈S1中
    	   while(!array.empty()) {
    		   stringArray.push(array.pop());//将栈S1中的数字压入栈S2中,那么输出栈S2就是后缀表达式
    	   }
    	   //获取后缀表达式
    	   while(!stringArray.empty()) {
    		   string.add(stringArray.pop());
    	   }
    	   return string;//返回后缀表达式
       }
       /**
        * 计算后缀表达式的值,通过配合栈来实现
        * 如果遇到的数字,那么就将数字压入栈中,否则,跳出两个数字,进行相应的运算,并将结果压入栈中,最后站还有一个数,那么这个数就是表达式的值
        * @param suffixExpression
        * @return
        */
       public int getSuffixExpressionResult(List<String> suffixExpression) {
    	   int result = 0;
    	   if(suffixExpression == null)
    		   throw new RuntimeException("后缀表达式为空,注意检查");
    	   //从左到右开始遍历
    	   for(int i = 0; i<suffixExpression.size(); i++) {
    		   String str = suffixExpression.get(i);
    		   if(isOper(str)) {
    			   //如果当前的字符是基本运算符,那么就从栈中条出两个数字,并进行相应的运算,之后将结果压入栈中
    			   //由于是从左到右开始遍历,那么应该是num2 - num1,num2 / num1
    			   int num1 = Integer.parseInt(array.pop());
    			   int num2 = Integer.parseInt(array.pop());
    			   if(str.equals("+"))
					   array.push(String.valueOf(num2 + num1));
				   else if(str.equals("-"))
					   array.push(String.valueOf(num2 - num1));
				   else if(str.equals("*"))
					   array.push(String.valueOf(num2 * num1));
				   else if(str.equals("/")) {
					   //注意除法的运算规则
					   if(num1 == 0)
						   throw new RuntimeException("除数不可以是0,运算式错误,注意检查");
					   else
						   array.push(String.valueOf(num2 / num1));
				   }
				   else{ 
				   if(num1 == 0)
    					throw new RuntimeException("除数不可以为0,表达式错误,不符合运算规则,注意检查");
					   array.push(String.valueOf(num2 % num1));
				 }
    		   }else {
    			   array.push(str);
    		   }
    	   }
    	   return Integer.parseInt(array.pop());
       }
       /**
        * 比较优先级
        * @param ch
        * @return
        */
       public int priority(String ch) {
    	   if(ch.equals("+") || ch.equals("-"))
    		   return 1;
    	   else if(ch.equals("*") || ch.equals("/"))
    		   return 2;
    	   else if(ch.equals("%"))
    		   return 3;
    	   else
    		   throw new RuntimeException("该符号不是基本运算符号,表达式错误,注意检查");
       }
       /**
        * 判断是否为基本运算符号
        * @param ch
        * @return
        */
       public boolean isOper(String ch) {
    	   return (ch.equals("+") || ch.equals("-") || ch.equals("*") || ch.equals("/") || ch.equals("%") || ch.equals("(") || ch.equals(")"));
       }
     
}

//主函数
import java.util.List;
import java.util.Scanner;

public class SuffixExpressionTestApp {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String infixExpression = sc.nextLine();
		String[] toSuffixExpression = infixExpression.split(" ");//将字符串分割成字符串数组
		SuffixExpressionTest test = new SuffixExpressionTest(toSuffixExpression);
		try{
			List<String> suffixExpression = test.getSuffixExpression(toSuffixExpression);//获得后缀表达式
			System.out.println(infixExpression +" 的后缀表达式为 " +suffixExpression);
			int result = test.getSuffixExpressionResult(suffixExpression);
			System.out.println(suffixExpression +" 的结果为 " + result);
		}catch(Exception e) {
			System.out.println(e.getMessage());
		}
		
	}

}

实现小数的基本一样的代码,不同的地方就是在进行运算的地方,它是将String类型转换成double类型,返回的也是double类型
代码如下:

/**
        * 计算后缀表达式的值,通过配合栈来实现
        * 如果遇到的数字,那么就将数字压入栈中,否则,跳出两个数字,进行相应的运算,并将结果压入栈中,最后站还有一个数,那么这个数就是表达式的值
        * @param suffixExpression
        * @return
        */
       public double getSuffixExpressionResult(List<String> suffixExpression) {
    	   int result = 0;
    	   if(suffixExpression == null)
    		   throw new RuntimeException("后缀表达式为空,注意检查");
    	   //从左到右开始遍历
    	   for(int i = 0; i<suffixExpression.size(); i++) {
    		   String str = suffixExpression.get(i);
    		   if(isOper(str)) {
    			   //如果当前的字符是基本运算符,那么就从栈中条出两个数字,并进行相应的运算,之后将结果压入栈中
    			   //由于是从左到右开始遍历,那么应该是num2 - num1,num2 / num1
    			   double num1 = Double.parseDouble(array.pop());
    			   double num2 = Double.parseDouble(array.pop());
    			   if(str.equals("+"))
					   array.push(String.valueOf(num2 + num1));
				   else if(str.equals("-"))
					   array.push(String.valueOf(num2 - num1));
				   else if(str.equals("*"))
					   array.push(String.valueOf(num2 * num1));
				   else if(str.equals("/")) {
					   //注意除法的运算规则
					   if(num1 == 0)
						   throw new RuntimeException("除数不可以是0,运算式错误,请注意检查,重新输入");
					   else
						   array.push(String.valueOf(num2 / num1));
				   }
				   else {
					   if(num1 == 0)
						   throw new RuntimeException("取模时除数不可以为0,运算式错误,请检查表达式,重新输入");
					   array.push(String.valueOf(num2 % num1));
				   }
    		   }else {
    			   array.push(str);
    		   }
    	   }
    	   return Double.parseDouble(array.pop());
       }

表达式的输入不需要用空格来隔开每一个字符的代码,如果有空格,就会报错,(同样这个代码是可以实现多位数字的,不过不可以实现含有小数的表达式,如果要实现含有小数,道理和上面一样的,在计算后缀表达式的时候,将每一个数字从栈中跳出,然后转换成double类型,然后返回的也是double就可以了,这里就不写它的代码了):

//主函数
import java.util.List;
import java.util.Scanner;

public class SuffixExpressionTestApp {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String infixExpression = sc.next();//输入中缀表达式(不可以用空格将每一个字符隔开,否则会报错)
		SuffixExpressionTest test1 = new SuffixExpressionTest(infixExpression);
		try{
			List<String> suffixExpression = test1.getSuffixExpression(infixExpression);//获得后缀表达式
			System.out.println(infixExpression +" 的后缀表达式为 " +suffixExpression);
			int result = test1.getSuffixExpressionResult(suffixExpression);
			System.out.println(suffixExpression +" 的结果为 " + result);
		}catch(Exception e) {
			System.out.println(e.getMessage());
		}		
	}
}
//调用这个类的方法,可以获得后缀表达式
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class SuffixExpressionTest {
       public Stack<String> array;
       public Stack<String> stringArray; 
       public int length ;
       //新建两个栈
       public SuffixExpressionTest(String infixExpression) {
    	   array = new Stack<String>();
    	   stringArray = new Stack<String>();
       }
       //获得后缀表达式
       public List<String> getSuffixExpression(String infixExpression) {
    	   if(infixExpression == null)
    		   throw new RuntimeException("字符串为空, 请输入字符串");
    	   List<String> string = new ArrayList<String>();
    	   String keepNum = "";//用来拼接多位数字的
    	   //从左到右开始遍历字符串
    	   for(int i = 0; i<infixExpression.length(); i++) {
    		   String ch = infixExpression.substring(i,i+1);//获得下标为i的字符串
    		   //判断是否为基本运算符
    		   if(isOper(ch)) {
    			   //如果是基本运算符,那么分情况讨论
    			   if(stringArray.empty() || stringArray.peek().equals("(")) {
    				   //如果栈为空, 或者栈顶是左括号,直接入栈
    				   stringArray.push(ch);
    			   }else if(ch.equals("(")) {
    				   //如果当前符号是左括号,那么直接入栈
    				   stringArray.push(ch);
    			   }else if(ch.equals(")")) {
    				   //如果当前符号是右括号,那么就将从栈S1中跳出2个数字,然后栈S2中跳出一个符号,进行相应的运算,将结果压入栈S1
    				   //重复上述操作,直到遇到左括号
    				   while(!stringArray.peek().equals("(")) {
    					   String temp = stringArray.pop();
    					   array.push(temp);
    				   }
    				   stringArray.pop();//将左括号从栈中跳出,消除左括号
    			   }else {
    				   //如果当前符号都不符合上面的几种情况,那么比较优先级
    				   if(priority(ch) > priority(stringArray.peek())) {
    					   stringArray.push(ch);//如果当前符号的优先级大于栈顶的优先级,那么直接将符号压入栈中
    				   }else {
    					   String temp = stringArray.pop();
    					   array.push(temp);
    					   stringArray.push(ch);//当前符号压入栈S2
    				   }
    			   }
    		   }else {
    			   //如果当前符号是数字,那么注意多位数字的拼接
    			   keepNum = ch;
    			   int j;
    			   for(j = i + 1; j<infixExpression.length(); j++) {
    				   String str = infixExpression.substring(j, j+ 1);
    				   if(isOper(str)) {
    					   break;
    				   }
    				   keepNum += str;//拼接多位数字
    			   }
    			   array.push(keepNum);
    			   keepNum = "";//将其重置为""
    			   i = j - 1;//注意这一步是必须的,因为退出循环的时候j对应的是非数字的下标,而在外部循环中又有i++,所以i = j - 1才可以,如果没有的话,那么就会少了一些字符
    		   }
    	   }
    	   //结束遍历之后,判断array是否为空,如果不为空,就将其所有元素压入栈stringArray中
    	   while(!array.empty()) {
    		   stringArray.push(String.valueOf(array.pop()));//将栈array中的数字压入栈stringArray中,那么输出栈stringArray就是后缀表达式
    	   }
    	   //获取后缀表达式
    	   while(!stringArray.empty()) {
    		   string.add(stringArray.pop());
    	   }
    	   return string;//返回后缀表达式
       }
       /**
        * 计算后缀表达式的值,通过配合栈来实现
        * 如果遇到的数字,那么就将数字压入栈中,否则,跳出两个数字,进行相应的运算,并将结果压入栈中,最后站还有一个数,那么这个数就是表达式的值
        * @param suffixExpression
        * @return
        */
       public int getSuffixExpressionResult(List<String> suffixExpression) {
    	   int result = 0;
    	   if(suffixExpression == null)
    		   throw new RuntimeException("后缀表达式为空,注意检查");
    	   //从左到右开始遍历
    	   for(int i = 0; i<suffixExpression.size(); i++) {
    		   String str = suffixExpression.get(i);
    		   if(isOper(str)) {
    			   //如果当前的字符是基本运算符,那么就从栈中条出两个数字,并进行相应的运算,之后将结果压入栈中
    			   //由于是从左到右开始遍历,那么应该是num2 - num1,num2 / num1
    			   int num1 = Integer.parseInt(array.pop());
    			   int num2 = Integer.parseInt(array.pop());
    			   if(str.equals("+"))
					   array.push(String.valueOf(num2 + num1));
				   else if(str.equals("-"))
					   array.push(String.valueOf(num2 - num1));
				   else if(str.equals("*"))
					   array.push(String.valueOf(num2 * num1));
				   else if(str.equals("/")) {
					   //注意除法的运算规则
					   if(num1 == 0)
						   throw new RuntimeException("除数不可以是0,运算式错误,注意检查");
					   else
						   array.push(String.valueOf(num2 / num1));
				   }else if(str.equals("%")) {
				   if(num1 == 0)
    					throw new RuntimeException("除数不可以为0,表达式错误,不符合运算规则,注意检查");
					   array.push(String.valueOf(num2 % num1));
				   }
    		   }else {
    			   array.push(str);
    		   }
    	   }
    	   return Integer.parseInt(array.pop());
       }
       /**
        * 比较优先级
        * @param ch
        * @return
        */
       public int priority(String ch) {
    	   if(ch.equals("+") || ch.equals("-"))
    		   return 1;
    	   else if(ch.equals("*") || ch.equals("/"))
    		   return 2;
    	   else if(ch.equals("%"))
    		   return 3;
    	   else
    		   throw new RuntimeException("该符号不是基本运算符号,表达式错误,注意检查");
       }
       /**
        * 判断是否为基本运算符号
        * @param ch
        * @return
        */
       public boolean isOper(String ch) {
    	   return (ch.equals("+") || ch.equals("-") || ch.equals("*") || ch.equals("/") || ch.equals("%") || ch.equals("(") || ch.equals(")"));
       }
     
}

2.2 中缀表达式转前缀表达式

2.2.1 思路

将中缀表达式转换为前缀表达式过程:

1)定义两个栈,其中一个栈是array,另一个栈是arrayString。

2)从右到左开始遍历表达式。

3)遇到数字,就将其压入到栈array,注意多位数字的情况。

4)遇到的是基本运算符,那么分几种情况讨论:
①如果栈arrayString为空 ,或者栈顶符号是右括号 ) , 或者当前符号是右括号 ) ,那么直接将当前符号压入栈arrayString中
②如果当前符号是左括号,那么就遍历栈arrayString,直到栈顶的符号不是右括号,否则就循环,同时再每一次循环中,要将栈arrayString中符号压入到栈array中,当结束循环以后,注意还要消除右括号,也就是再次将S2的符号跳出一次
③如果当前的符号都不符合上面几种情况,那么将当前符号和栈顶的符号进行比较优先级
(1)如果当前符号的优先级大于或者等于栈顶的优先级,那么直接将符号压入栈arrayString
(2)否则,如果当前符号的优先级小于栈顶的优先级,那么先从栈arrayString跳出栈顶的符号,然后将其压入到栈array中,最后将当前符号压入到栈arrayString中

正确进行比较优先级时的结果
在这里插入图片描述

错误进行比较优先级(就是和转后缀表达式一样,当前符号的优先级大于栈顶符号的优先级,直接将当前符号压入栈arrayString,否则,先将栈顶符号从栈arrayString跳出,然后将其压入栈array,最后将当前符号压入栈arrayString)的结果:
在这里插入图片描述
5)遍历结束之后,将
arrayString中的所有元素压入到array中

在这里插入图片描述

由图解可知,将栈arrayString的元素都压入栈array,将array遍历输出的就是前缀表达式。如果将栈array的元素都压入栈arrayString,然将arrayString遍历输出的是前缀表达式的倒序

6)遍历array,将其元素赋给一个字符串列表List,那么这个列表就是要求的前缀表达式。(关于为什么是列表而不是数组的讨论,上面中缀表达式转后缀表达式已经讨论过了,这里就不说了哈)。

2.2.2 代码实现:

1)表达式要求是每一个字符都用一个空格间隔开,这样的话,在处理多位数字(没有小数)的问题上,不需要定义一个变量用于拼接,也不需要在一次循环。如果没有空格的话,会出错

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PrefixExpression {
	public Stack<String> array;
    public Stack<String> stringArray;
    public int length;
    public PrefixExpression(String[] infixExpression) {
    	length = infixExpression.length;
    	array = new Stack<String>();
    	stringArray = new Stack<String>();
    }
    public List<String> getPrefixExpression(String[] infixExpression) {
    	if(infixExpression == null) {
    	    throw new RuntimeException("链表为空,请输入字符串");
    	}
    	List<String> str = new ArrayList<String>();
    	//从右到左开始遍历字符串
    	for(int i = length - 1; i >= 0; i --) {
    		String ch = infixExpression[i];//获得当前的字符
    		//判断当前字符是否为基本运算符
    		if(isOper(ch)) {
    			//如果栈为空,或者栈顶的符号是右括号,或者当前符号是右括号,那么直接入栈
    			if(stringArray.empty() || ch.equals(")") || stringArray.peek().equals(")") )
    				stringArray.push(ch);
    			else if(ch.equals("(")) {
    				//如果当前符号是左括号,那么遍历,将栈stringArray中的元素压入到栈array中去,直到遇到右括号
    				while(!stringArray.peek().equals(")")) {
    					array.push(stringArray.pop());
    				}
    				stringArray.pop();//消除右括号
    			}else {
    				//如果当前符号都不符合上面几种情况,那么比较优先级
    				if(priority(ch) >= priority(stringArray.peek())) {
    					//如果当前符号的优先级比栈顶的优先级高或者相等,那么就将直接入栈
    					stringArray.push(ch);
    				}else {
    					//否则,如果当前符号的优先级小于栈顶的优先级,那么先将栈顶的符号压入到栈array,然后才将当前符号压入到stringArray中
    					array.push(stringArray.pop());
    					stringArray.push(ch);
    				}
    			}
    		}else {
    			array.push(ch);//将数字压入到栈S1
    		}
    	}
    	while(!stringArray.empty()) {//将stringArray的所有元素压入到栈array中
    		array.push(stringArray.pop());
    	}
    	while(!array.empty()) {//遍历栈array,,然后将其赋给字符串列表
    		str.add(array.pop());
    	}
    	return str;//返回前缀表达式
    }
    /**
     *计算前缀表达式的值 --通过栈来实现,从右到左开始遍历,如果遇到的是数字,那么将数字压入栈中,否则遇到的是运算符,那么就进行运算(注意运算法则)
     * @param prefixExpression  前缀表达式
     * @return  前缀表达式的结果
     */
    public int getPrefixExpressionResult(List<String> prefixExpression) {
    	//从右到左开始遍历
    	for(int i = prefixExpression.size() - 1; i >= 0; i--) {
    		String ch = prefixExpression.get(i);
    		if(isOper(ch)) {
    			//如果是运算符,那么将跳出两个数字,进行相应的运算,然后将结果压入栈中
    			int num1 = Integer.parseInt(array.pop());
    			int num2 = Integer.parseInt(array.pop());
    			if(ch.equals("-"))
    				array.push(String.valueOf(num1 - num2));//注意将结果转换成整形,同时注意是num1 - num2,而不是num2 - num1,下面同理
    			else if(ch.equals("+"))
    				array.push(String.valueOf(num2 + num1));//注意将结果转换成整形
    			else if(ch.equals("*"))
    				array.push(String.valueOf(num1 * num2));//注意将结果转换成整形
    			else if(ch.equals("/")) {
    				if(num2 == 0)
    					throw new RuntimeException("除数不可以为0,表达式错误,不符合运算规则,注意检查");
    				array.push(String.valueOf(num1 / num2));//注意将结果转换成整形
    			}else if(ch.equals("%")) {
    			    if(num2 == 0)
    					throw new RuntimeException("取模时除数不可以为0,表达式错误,不符合运算规则,注意检查");
    				array.push(String.valueOf(num1 % num2));//注意将结果转换成整形
    			}	
    		}else {
    			array.push(ch);//如果不是运算符,那么就将其压入栈中 --考虑多位数字的存在
    		}
    	}
    	return Integer.parseInt(array.pop());
    }
    /**
     * 比较优先级
     * @param ch
     * @return
     */
    public int priority(String ch) {
 	   if(ch.equals("+") || ch.equals("-"))
 		   return 1;
 	   else if(ch.equals("*") || ch.equals("/"))
 		   return 2;
 	   else if(ch.equals("%"))
 		   return 3;
 	   else
 		   throw new RuntimeException("该符号不是基本运算符号,表达式错误,注意检查");
    }
    /**
     * 判断是否为基本运算符号
     * @param ch
     * @return
     */
    public boolean isOper(String ch) {
 	   return (ch.equals("+") || ch.equals("-") || ch.equals("*") || ch.equals("/") || ch.equals("%") || ch.equals("(") || ch.equals(")"));
    }
}



//主函数
import java.util.List;
import java.util.Scanner;

public class PrefixExpressionApp {
       public static void main(String[] args) {
    	   Scanner sc = new Scanner(System.in);
    	   String infixExpression = sc.nextLine();
    	   String[] toInfixExpression = infixExpression.split(" ");//将字符串分割成字符串数组
    	   PrefixExpression test = new PrefixExpression(toInfixExpression);
    	   List<String> prefixExpression = test.getPrefixExpression(toInfixExpression);//获得前缀表达式
    	   System.out.print(infixExpression +" 的前缀表达式为:  ");
    	   System.out.println(prefixExpression);
    	   try {
    		   int result = test.getPrefixExpressionResult(prefixExpression);
    		   System.out.println(prefixExpression +" 的结果为 "+ result);
    	   }catch(Exception e) {
    		   System.out.println(e.getMessage());
    	   }
       }
}

表达式输入要有一个空将每一个字符间隔开时,处理含有小数时方法和处理后缀表达式中含有小数的方法一样,都是在进行运算的时候,将每一个数字从栈中跳出,然后转化成double类型,在进行运算,最后返回double类型就可以了,这里就不写了)

2)表达式没有空格(处理多位数字,不含小数):

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PrefixExpression {
	public Stack<String> array;
    public Stack<String> stringArray;
    public int length;
    public PrefixExpression(String infixExpression) {
    	length = infixExpression.length();
    	array = new Stack<String>();
    	stringArray = new Stack<String>();
    }
    public List<String> getPrefixExpression(String infixExpression) {
    	if(infixExpression == null) {
    	    throw new RuntimeException("链表为空,请输入字符串");
    	}
    	List<String> str = new ArrayList<String>();
    	//从右到左开始遍历字符串
    	for(int i = length - 1; i >= 0; i --) {
    		String ch = infixExpression.substring(i,i+1);//获得当前的字符
    		//判断当前字符是否为基本运算符
    		if(isOper(ch)) {
    			//如果栈为空,或者栈顶的符号是右括号,或者当前符号是右括号,那么直接入栈
    			if(stringArray.empty() || ch.equals(")") || stringArray.peek().equals(")") )
    				stringArray.push(ch);
    			else if(ch.equals("(")) {
    				//如果当前符号是左括号,那么遍历,将栈stringArray中的元素压入到栈array中去,直到遇到右括号
    				while(!stringArray.peek().equals(")")) {
    					array.push(stringArray.pop());
    				}
    				stringArray.pop();//消除右括号
    			}else {
    				//如果当前符号都不符合上面几种情况,那么比较优先级
    				if(priority(ch) >= priority(stringArray.peek())) {
    					//如果当前符号的优先级比栈顶的优先级高或者相等,那么就将直接入栈
    					stringArray.push(ch);
    				}else {
    					//否则,如果当前符号的优先级小于栈顶的优先级,那么先将栈顶的符号压入到栈array,然后才将当前符号压入到stringArray中
    					array.push(stringArray.pop());
    					stringArray.push(ch);
    				}
    			}
    		}else {
    			//如果是数字,那么注意多位数字的拼接
    			int result = Integer.parseInt(ch);
    			int k,j;
    			for(j = i - 1,k = 10; j>= 0; j--,k *= 10) {
    				String temp = infixExpression.substring(j,j + 1);
    				if(isOper(temp)) {
    					break;
    				}
    				//由于是从右到左开始遍历的,所以不可以直接是keepNum += temp,因为如果是这样拼接多位数字的话会错误,因为将14倒过来了,变成了41
    				result += Integer.parseInt(temp) * k;
    			}
    			array.push(String.valueOf(result));//将数字压入到栈S1
    			i = j + 1;//这一步是必须,(原因和转后缀表达式那里类似,关键是因为遍历的顺序,所以是加还是减,要看遍历的顺序,这里就不说了哈)
    		}
    	}
    	while(!stringArray.empty()) {
    		array.push(stringArray.pop());
    	}
    	while(!array.empty()) {
    		str.add(array.pop());
    	}
    	return str;
    }
    /**
     *计算前缀表达式的值 --通过栈来实现,从右到左开始遍历,如果遇到的是数字,那么将数字压入栈中,否则遇到的是运算符,那么就进行运算(注意运算法则)
     * @param prefixExpression  前缀表达式
     * @return  前缀表达式的结果
     */
    public int getPrefixExpressionResult(List<String> prefixExpression) {
    	//从右到左开始遍历
    	for(int i = prefixExpression.size() - 1; i >= 0; i--) {
    		String ch = prefixExpression.get(i);
    		if(isOper(ch)) {
    			//如果是运算符,那么将跳出两个数字,进行相应的运算,然后将结果压入栈中
    			int num1 = Integer.parseInt(array.pop());
    			int num2 = Integer.parseInt(array.pop());
    			if(ch.equals("-"))
    				array.push(String.valueOf(num1 - num2));//注意将结果转换成整形
    			else if(ch.equals("+"))
    				array.push(String.valueOf(num2 + num1));//注意将结果转换成整形
    			else if(ch.equals("*"))
    				array.push(String.valueOf(num1 * num2));//注意将结果转换成整形
    			else if(ch.equals("/")) {
    				if(num2 == 0)
    					throw new RuntimeException("除数不可以为0,表达式错误,不符合运算规则,注意检查");
    				array.push(String.valueOf(num1 / num2));//注意将结果转换成整形
    			}else if(ch.equals("%")) {
    			    if(num2 == 0)
    					throw new RuntimeException("取模时除数不可以为0,表达式错误,不符合运算规则,注意检查");
    				array.push(String.valueOf(num1 % num2));//注意将结果转换成整形
    			}	
    		}else {
    			array.push(ch);//如果不是运算符,那么就将其压入栈中 --考虑多位数字的存在
    		}
    	}
    	return Integer.parseInt(array.pop());
    }
    /**
     * 比较优先级
     * @param ch
     * @return
     */
    public int priority(String ch) {
 	   if(ch.equals("+") || ch.equals("-"))
 		   return 1;
 	   else if(ch.equals("*") || ch.equals("/"))
 		   return 2;
 	   else if(ch.equals("%"))
 		   return 3;
 	   else
 		   throw new RuntimeException("该符号不是基本运算符号,表达式错误,注意检查");
    }
    /**
     * 判断是否为基本运算符号
     * @param ch
     * @return
     */
    public boolean isOper(String ch) {
 	   return (ch.equals("+") || ch.equals("-") || ch.equals("*") || ch.equals("/") || ch.equals("%") || ch.equals("(") || ch.equals(")"));
    }
}



//主函数
import java.util.List;
import java.util.Scanner;

public class PrefixExpressionApp {
       public static void main(String[] args) {
    	   Scanner sc = new Scanner(System.in);
    	   String infixExpression = sc.next();//输入的是没有空格的表达式
    	   PrefixExpression test = new PrefixExpression(infixExpression);
    	   List<String> prefixExpression = test.getPrefixExpression(infixExpression);//获得前缀表达式
    	   System.out.print(infixExpression +" 的前缀表达式为:  ");
    	   System.out.println(prefixExpression);
    	   try {
    		   int result = test.getPrefixExpressionResult(prefixExpression);
    		   System.out.println(prefixExpression +" 的结果为 "+ result);
    	   }catch(Exception e) {
    		   System.out.println(e.getMessage());
    	   }
       }
}

表达式没有用一个空格隔开每一个字符的,处理多为数字的时候,需要注意小数的拼接(因为他是从右到左开始遍历,那么就不像后缀表达式那样,通过用一个字符串就可以实现小数的拼接),而在运算的时候,和上面的方式一样,都是将从栈中跳出数字,然后将其类型转换成double类型,最后返回double类型。

拼接小数时的代码(我将返回前缀表达式的代码都写了,重点看拼接数字那里的代码就好了):

    public List<String> getPrefixExpression(String infixExpression) {
        if(infixExpression == null) {
            throw new RuntimeException("链表为空,请输入字符串");
        }
        List<String> str = new ArrayList<String>();
        //从右到左开始遍历字符串
        for(int i = length - 1; i >= 0; i --) {
            String ch = infixExpression.substring(i,i+1);//获得当前的字符
            //判断当前字符是否为基本运算符
            if(isOper(ch)) {
                //如果栈为空,或者栈顶的符号是右括号,或者当前符号是右括号,那么直接入栈
                if(stringArray.empty() || ch.equals(")") || stringArray.peek().equals(")") )
                    stringArray.push(ch);
                else if(ch.equals("(")) {
                    //如果当前符号是左括号,那么遍历,将栈S2中的元素压入到栈S1中去,直到遇到右括号
                    while(!stringArray.peek().equals(")")) {
                        array.push(stringArray.pop());
                    }
                    stringArray.pop();//消除左括号
                }else {
                    //如果当前符号都不符合上面几种情况,那么比较优先级
                    if(priority(ch) >= priority(stringArray.peek())) {
                        //如果当前符号的优先级比栈顶的优先级高或者相等,那么就将直接入栈
                        stringArray.push(ch);
                    }else {
                        //当前符号的优先级小于栈顶的优先级,那么先将栈顶的符号压入到栈S1,然后才将当前符号压入到S2中
                        array.push(stringArray.pop());
                        stringArray.push(ch);
                    }
                }
            }else {
                //如果是数字,那么注意多位数字的拼接
                double result = Double.parseDouble(ch);
                boolean con = false;//标记是否含有小数点
                int k,j,count = 0;
                for(j = i - 1,k = 10; j>= 0; j--) {
                    String temp = infixExpression.substring(j,j + 1);
                    if(isOper(temp)) {
                        break;
                    }else if(temp.equals(".")){
                        con = true;
                        continue;
                    }else {//由于是从右到左开始遍历的,所以不可以直接是keepNum += temp,因为如果是这样拼接多位数字的话会错误,因为将14倒过来了,变成了41
                        if(con){
                            //如果是小数,那么看小数点之前有多少位数字
                            count ++;
                        }
                        result += Double.parseDouble(temp) * k;
                        k *= 10;
                    }
                }
                if(con)//如果含有小数点,需要将结果整理,从而得到小数
                     result /= (k / Math.pow(10,count));//这个可以举例子说明的,比如如果数字是77.9,那么在经过遍历拼接之后,result = 779,count = 2,k = 1000,那么经过这一步就是77.9了 
                array.push(String.valueOf(result));//将数字压入到栈array
                i = j + 1;//这一步是必须,(原因和转后缀表达式那里类似,关键是因为遍历的顺序,所以是加还是减,要看遍历的顺序,这里就不说了哈)
            }
        }
        while(!stringArray.empty()) {
            array.push(stringArray.pop());
        }
        while(!array.empty()) {
            str.add(array.pop());
        }
        return str;
    }
  • 8
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值