四则运算求值(中缀转逆波兰式)

参照leno_a大牛的代码自己练习了一遍中缀转后缀的算法,写个类自用

package javatestcode;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

interface Operation{
	BigDecimal apply(BigDecimal arg1,BigDecimal arg2);
}

public class RevertPoland{
	/**
	 * 使用枚举形式定义各种操作符
	 * @author bandw
	 *
	 */
	enum Operator implements Operation {
		PlUS("+",2) {
			public BigDecimal apply(BigDecimal arg1,BigDecimal arg2) {
				return arg1.add(arg2);
			}
		},
		MINUS("-",2) {
			public BigDecimal apply(BigDecimal arg1,BigDecimal arg2) {
				return arg1.subtract(arg2); 
			}
		},
		TIMES("*",3) {
			public BigDecimal apply(BigDecimal arg1,BigDecimal arg2) {
				return arg1.multiply(arg2);
			}
		},
		DIVIDE("/",3) {
			public BigDecimal apply(BigDecimal arg1,BigDecimal arg2) {
				return arg1.divide(arg2);
			}
		},
		LEFTPAREN("(",4){
			public BigDecimal apply(BigDecimal arg1,BigDecimal arg2) {
				throw new UnsupportedOperationException();
			}
		},
		RIGHTPAREN(")",4){
			@Override
			public BigDecimal apply(BigDecimal arg1, BigDecimal arg2) {
				throw new UnsupportedOperationException();
			}
			
		}
		;
		
		/**
		 * 操作符的符号<br></br> 
		 * 如乘号的symbol为 "*"
		 */
		private final String symbol;
		/**
		 * 操作符的优先级<br></br>
		 * 数字大为优先级高
		 */
		private final int priority;
		Operator(String symbol,int priority){
			this.symbol=symbol;
			this.priority=priority;
		}
		
		
		
		public int getPriority() {
			return priority;
		}



		public String toString(){
			return this.symbol;
		}
		/**
		 * 通过操作符符号判断该符号是否为操作符
		 * @param symbol  操作符的符号
		 * @return 返回判断结果
		 */
		 public static boolean isOperator(String symbol){
		       for(Operator oper:values()){
		    	   if(oper.symbol.equals(symbol)) return true;
		       }
		       return false;
		 }
		 /**
		  *  通过操作符符号返回操作符的枚举类型
		  * @param symbol 操作符的符号
		  * @return 对应操作符枚举类型
		  */
		 public static Operator fromSymbol(String symbol){
			 for(Operator oper:values()){
		    	   if(oper.symbol.equals(symbol)) return oper;
		       }
		       return null;
		 }
		 
	}
	
	/**
	 * 保留转换后的逆波兰式元素栈<br></br>
	 * toString方法直接通过元素栈生成字符串,避免重新执行转换算法
	 */
	 private LinkedList<Object> polandExpElement=null;
	
	/**
	 * 利用逆波兰式元素栈计算出来的结果
	 */
	private BigDecimal result=null;
	/**
	 * 构造方法<br></br>
	 * 初始化时类时已经执行转换算法,结果存放在逆波兰式元素栈中
	 * @param infixExpression 中缀表达式
	 */
    public RevertPoland(String infixExpression){
    	polandExpElement=convertToPoland(infixExpression);
    }
    
    public BigDecimal getResult() {
		return result;
	}

	/**
     * 利用逆波兰式元素栈计算结果,结果放在内部属性result中
     * @return 计算结果
     */
    public BigDecimal calculate(){
    	
    	LinkedList<Object> resultStack=new LinkedList<Object>();
    	Iterator<Object> iter=polandExpElement.descendingIterator();
    	//一个一个元素压栈,如果栈顶元素为操作符,操作符出栈,再将顶上的两个数字出栈,对两个数字进行运算
    	while(iter.hasNext()){
    		resultStack.push(iter.next());	
    		if(resultStack.peek() instanceof Operator){
    			Operator operator=(Operator)resultStack.pop();
    			 BigDecimal arg1=(BigDecimal)resultStack.pop();
    			 BigDecimal arg2=(BigDecimal)resultStack.pop();
    			 BigDecimal result=operator.apply(arg2, arg1);
    			 resultStack.push(result);
    		}

    	}
    	result=(BigDecimal)resultStack.pop();
    	return result;
    }
    
    /**
     * 将中缀表达式转换为逆波兰式
     * @param infixExpression 中缀表达式
     * @return 逆波兰式元素栈
     */
    private LinkedList<Object> convertToPoland(String infixExpression){
    	if(infixExpression==null||infixExpression.equals("")) return null;
    	
    	List<Object> element=pickExpressionElement(infixExpression);
    	//逆波兰式元素栈
    	LinkedList<Object> expElementStack=new LinkedList<Object>();
    	//操作符栈
    	LinkedList<Operator> operatorStack=new LinkedList<Operator>();

    	for(Object obj:element){
    		//数字压栈
    	    if(obj instanceof BigDecimal){
    	    	expElementStack.push(obj);
    	    }
    		else if(obj instanceof Operator){
    			//如果是右括号 则操作符栈内元素送入逆波兰式元素栈中,直到退出左括号
    			if(obj == Operator.RIGHTPAREN){
    				while(operatorStack.peek()!=Operator.LEFTPAREN){
    					expElementStack.push(operatorStack.pop());
    				}
    				//左括号出栈,丢弃
    				operatorStack.pop();
    			}
    			//如果当前操作符比操作符栈顶元素优先级小或者相等,操作符栈顶元素送入逆波兰式元素栈中,
    			//直至当前操作符比操作符栈顶元素优先级大或者操作符栈顶元素为左括号
    			else {
    				while(operatorStack.peek()!=null
    						&& operatorStack.peek() != Operator.LEFTPAREN	
    						&& ((Operator)obj).getPriority() <= operatorStack.peek().getPriority()){
	    				
    					expElementStack.push(operatorStack.pop());
	    				
    				}
    				operatorStack.push((Operator)obj);
    				
    			}
    		}
    	}
    	//表达式元素读取结束,剩下在操作符栈内的元素逐一送入逆波兰式元素栈中
    	while(operatorStack.peek()!=null){
    		expElementStack.push(operatorStack.pop());
    	}
    	return expElementStack;
    }
    
    /**
     * 从表达式中提取表达式元素<br></br>
     * <ul>
     * <li>数字用BigDecimal储存</li>
     * <li>操作符用内部类Operator储存</li>
     * </ul>
     * @param expression 字符串表达式
     * @return 表达式元素列表
     */
    private LinkedList<Object> pickExpressionElement(String expression){
    	//匹配数字的正则表达式
    	String decimalRegex="\\d+\\.{0,1}\\d*";
    	Pattern pattern=Pattern.compile(decimalRegex);
    	Matcher matcher=pattern.matcher(expression);
    	
    	LinkedList<Object> expElement= new LinkedList<Object>();
    	ArrayList<BigDecimal> decimals=new ArrayList<BigDecimal>();
    	//将数字一个个匹配出来
    	while (matcher.find()) {
    		   decimals.add(new BigDecimal(matcher.group()));	    
    	}
    	//将字符串数字部分转为@ 如 1+2*3.5 将转为 @+@*@
    	String tempString=expression.replaceAll(decimalRegex, "@");
    	
    	//System.out.println(tempString);
    	//解释转换后的字符串,遇@则将一个数字添加到表达式元素列表中,遇操作符将对应操作符添加到表达式元素列表
    	char[] charArray=tempString.toString().toCharArray();
    	for(int j=0,numIndex=0;j<charArray.length;j++){
    		if(charArray[j]=='@'){
    			expElement.add(decimals.get(numIndex++));
    			
    		}
    		else {
    			String symbol=String.valueOf(charArray[j]);
    			if(Operator.isOperator(symbol)){
    				expElement.add(Operator.fromSymbol(symbol));
    			}
    		}
    	}
    	return expElement;
    }
    
    public String toString(){
    	StringBuffer polandExpression=new StringBuffer();

    	Iterator<Object> iter=polandExpElement.descendingIterator();
    	while(iter.hasNext())
    	 polandExpression.append(iter.next()+" ");
    	 
    	return polandExpression.toString();
    }
    
	public static void main(String[] args){
		RevertPoland poland=new RevertPoland("4-(4-3*5+(2*4)+100)/10");
		System.out.println(poland);
		System.out.println(poland.calculate());
	}
	
}

 参考: leno_a大牛的代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值