用逆波兰表达式实现表达式计算

表达式求值计算,如计算1+((2+3)*4)-5的值。

我的思路是先把表达式转换为逆波兰表达式,因为逆波兰表达式更加符合计算机的处理逻辑,把表达式转换为逆波兰表达式的算法如下:

  1. 初始化两个栈:运算符栈s2和储存中间结果的栈s1;
  2. 从左至右扫描中缀表达式;
  3. 遇到操作数时,将其压s1;
  4. 遇到运算符时,比较其与s2栈顶运算符的优先级:
    1. 如果s2为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
    2. 否则,若优先级比栈顶运算符的高,也将运算符压入s2(注意转换为前缀表达式时是优先级较高或相同,而这里则不包括相同的情况);
    3. 否则,将s2栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s2中新的栈顶运算符相比较;
  5. 遇到括号时:
    1. 如果是左括号“(”,则直接压入s2;
    2. 如果是右括号“)”,则依次弹出s2栈顶的运算符,并压入s1,直到遇到左括号为止,此时将这一对括号丢弃;
  6. 重复步骤2至5,直到表达式的最右边;
  7. 将s2中剩余的运算符依次弹出并压入s1

 

后缀表达式求值的算法如下:

   首先定义一个栈:S3,在该栈中存放最终表达式的值。从左到右遍历S1,然后按照如下规则操作S3:

(1)如果遇到的是数字,将数字压入S3中;

(2)如果遇到单目运算符(运算对象只有一个的运算符,如:或(|)、与(&)等),取S3栈顶一个元素进行单目运算,将结果再次压入S3中;

(3)如果遇到双目运算符(运算对象有两个的运算符,如:加(+)、赋值(=)等),取S3栈顶两个元素(先出栈的在左,后出栈的在右)进行 双目运算,将结果再次压入S3中;

按照上面3条规则遍历完S1,那么最后S3中的值就是逆波兰表达式的值了。

  下面是我用java的代码实现

  

package com.sun.calculation;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

/***
 * 中缀表达式计算例如1+((2+3)*4)-5
 * 实现思路就是先把中缀表达式转换为逆波兰表达式
 * 然后再对逆波兰表达式表达式进行计算
 * @author swh
 *
 */
public class ExpressionComputation {

	/***
	 * 先把中缀表达式转换为后缀表达式
	 * 再对后缀表达式进行计算
	 * @param expression 中缀表达式
	 * @return
	 */
	public static int computation(String expression) {
		
		return getRpnValue(getRpn(expression));
	}

	/***
	 * 中缀表达式转换为后缀表达式
	 * @param expression
	 * @return
	 */
	private static Queue<Object> getRpn(String expression) {
		Queue<Object> valueQueue = new LinkedList<>();
		Stack<String> optStack = new Stack<>();
		String munStr = ""; 
	    for(int i=0;i<expression.length();i++) {
	    	char ch = expression.charAt(i);
	    	String str = String.valueOf(ch);
	    	if(ch>='0'&&ch<='9') {
	    		munStr +=str;
	    	}else {
	    		if(!munStr.equals("")) {
	    			valueQueue.add(Integer.valueOf(munStr));
	    			munStr="";
	    		}
	    		if (ch=='(') {
	    			optStack.push(str);
	    		}else if (ch==')')  {
	    			  while (optStack.size()!=0&&!optStack.peek().equals("(")) {
	    				  valueQueue.add(optStack.pop());
	                  }
	    			  optStack.pop();
	    		}else {
	    			 while (optStack.size() != 0&&getOptionLevel(optStack.peek())>=getOptionLevel(str)) {
	    				 valueQueue.add(optStack.pop());
	                  }
	    			 optStack.push(str);
	    		}
	    	}
	    }
	    valueQueue.add(Integer.valueOf(munStr));
	    while (optStack.size()!=0) {
			 valueQueue.add(optStack.pop());
         }
	    return valueQueue;
	}
	
	/***
	 * 对后缀表达式进行计算
	 * @param valueQueue
	 * @return
	 */
	public static int getRpnValue(Queue<Object> valueQueue) {
		Stack<Integer> numStack = new Stack<>();
		while(!valueQueue.isEmpty()) {
			if(valueQueue.peek() instanceof Integer) {
				numStack.push((Integer)valueQueue.poll());
			}else {
				String operation = (String)valueQueue.poll();
				numStack.push(getOptionValue(operation, numStack.pop(), numStack.pop()));
			}
		}
		return numStack.pop();
	}
	/***
	 * 得到运算符的优先级
	 * @param opt
	 */
	public static int getOptionLevel(String operation) {
		 int result = 0;
	        switch (operation){
	            case "+":
	                result=1;
	                break;
	            case "-":
	                result=1;
	                break;
	            case "*":
	                result=2;
	                break;
	            case "/":
	                result=2;
	                break;
	        }
	        return result;
	}
	
	/***
	 * 得到二元运算的值
	 * @param operation
	 * @param b
	 * @param a
	 * @return
	 */
	public static int getOptionValue(String operation,int b,int a) {
		 int result = 0;
	        switch (operation){
	            case "+":
	                result=a+b;
	                break;
	            case "-":
	                result=a-b;
	                break;
	            case "*":
	                result=a*b;
	                break;
	            case "/":
	                result=a/b;
	                break;
	        }
	        return result;
	}
	public static void main(String args[]) {
		computation("1+((2+3)*4)-5");
	}
}

  参考了博客:

   前缀、中缀、后缀表达式(逆波兰表达式

  逆波兰表达式算法

猜你喜欢

转载自blog.csdn.net/swh1314/article/details/82764729