`
mingjian01
  • 浏览: 29589 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

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

阅读更多

参照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大牛的代码

分享到:
评论

相关推荐

    C语言通过逆波兰式实现四则运算

    通过把输入的中缀表达示转换为逆波兰式实现整数及小数的四则运算,为了简便,这个程序只支持小括号,中括号和大括号暂不支持,需要的话自己插入几句代码就行了。 gcc下编译通过,没在window下测试。

    C#逆波兰式计算器

    逆波兰式计算器是一种基于后缀表示法(也称为逆波兰表示法)的计算模型...掌握这些技能对于C#程序员来说是至关重要的,因为它们不仅适用于逆波兰式计算器,还可以应用于编译器设计、表达式求值、解析器构建等多个领域。

    C逆波兰式(是用c实现的)

    逆波兰式计算相对简单,只需要从左至右扫描逆波兰式,遇到数字则压入栈中,遇到操作符则从栈中弹出两个操作数进行运算,将结果再次压入栈中。最终,栈顶元素即为整个表达式的计算结果。 #### 四、逆波兰式的优势 ...

    js库实现中缀表达式(即日常使用的四则运算表达式)转换成后缀表达式(逆波兰式),方便计算机计算

    然而,计算机处理这种表达式时不如处理后缀表达式(逆波兰式)来得直接。后缀表达式是将运算符放在操作数之后的形式,例如,上述中缀表达式对应的后缀表达式为 \(2 3 4 * +\)。这样的表示方式使得求值过程无需使用栈...

    java带逆波兰式的科学计算器

    - **科学计算功能**:除了基本的四则运算,科学计算器还可能包括对数、指数、平方根、三角函数等高级运算。这些可以通过调用Java Math库中的相应方法实现。 大三学生用Java编写逆波兰式计算器是一个很好的学习项目...

    Android 带滑动、抽屉效果的逆波兰式计算器

    4. **四则运算**:计算器的核心功能,包括加法、减法、乘法和除法。在逆波兰式计算过程中,需要处理这些基本的数学运算。例如,遇到"+"时,取出栈顶的两个数相加,结果再入栈;同理,"-"、"*"和"/"分别对应减法、...

    编译原理逆波兰算法及四元式

    逆波兰算法和四元式在编译原理中的结合应用可以简化表达式求值的过程,使得编译器能够更高效地处理和优化代码。四元式易于理解,方便进行优化和错误检测,而逆波兰算法则提供了一种无需考虑括号匹配的简便计算方式。...

    xauat软件工程课程设计,计算器任务,安德学院大作业,逆波兰式,中缀表达式,连接器

    根据提供的文件信息,以下是对“xauat软件工程课程设计,计算器任务,安德学院大作业,逆波兰式,中缀表达式,连接器”的知识点的详细阐述: 1. 软件工程课程设计概念 在软件工程领域,课程设计是一个重要的环节,...

    中缀式构造后缀式实验报告

    然而,在计算机处理过程中,后缀式(也称为逆波兰式)表达式更便于计算,因为它避免了括号的使用,通过运算符的顺序来确定计算顺序。本实验旨在将中缀表达式转化为后缀表达式,这是一个典型编译原理中的问题,涉及到...

    表达式计算器,支持四则与括号运算(C++)

    逆波兰表示法是一种将运算符放在操作数之后的表示方式,它简化了表达式求值的过程,尤其适用于编译器和计算器的设计。 首先,我们需要了解四则运算,即加法(+)、减法(-)、乘法(*)和除法(/)。在传统的中缀表达式...

    mfc逆波兰计算器

    这个“mfc逆波兰计算器”项目利用MFC框架来创建一个图形用户界面,使得用户可以进行四则运算、括号处理以及进制转换。 首先,我们来了解一下逆波兰表示法。在常规的数学表达式中,我们使用运算符的优先级和括号来...

    java控制台四则运算计算程序源码

    3. **中缀表达式与后缀表达式**:为了简化运算,可以将用户输入的中缀表达式(运算符在操作数之间)转换为后缀表达式(运算符在操作数之后,也称为逆波兰表示法)。后缀表达式可以更方便地用栈来计算,因为只需要...

    四则运算c语言

    在计算机科学中,四则运算(加法、减法、乘法、除法)是基本的算术操作,而C语言是一种广泛使用的编程语言,它提供了处理这些运算的强大功能。后缀表达式,也称为逆波兰表示法,是一种在没有括号和运算符优先级的...

    带括号的四则多项运算

    6. **中缀表达式与后缀表达式(逆波兰表示法)**:中缀表达式是我们常见的运算式形式,如 "2 + 3 * 4"。后缀表达式,也称为逆波兰表示法,如 "2 3 4 * +",运算符放在其操作数之后,无需括号就能明确运算顺序。后缀...

    c#写带括号的四则运算计算器带源码,

    3. **中缀表达式与后缀表达式(逆波兰表示法)**:由于C#不支持直接解析带有括号的中缀表达式,所以通常会将中缀表达式转化为后缀表达式(逆波兰表示法),这样可以简化计算过程。中缀表达式是常规的加减乘除运算...

    离散数学MFC做的支持四则运算的 计算器

    计算过程可能涉及栈的数据结构,因为四则运算遵循后缀表达式(逆波兰表示法)或中缀表达式的转换规则。后缀表达式可以简化计算过程,因为它避免了括号和运算优先级的问题。 对于加减乘除的实现,可以创建一个自定义...

    能进行四则混合运算的计算器

    1. **基本算术运算**:每个四则运算符都有其特定的运算规则。例如,加法和减法具有左结合性,乘法和除法的优先级高于加法和减法,但它们之间没有优先级差异,都是从左到右进行计算。程序需要处理这些运算规则。 2. ...

    四则表达式计算BCB2010实现

    专贡 http://topic.csdn.net/u/20100826/16/39e4362b-9fea-4ee7-b3d9-cfc1af2eb67e.html?seed=780179899&r=67978419#r_67978419

    带抽屉滑动效果

    在编程中,逆波兰式通常用于实现计算器功能,例如这里提到的"支持四则运算"。四则运算包括加法、减法、乘法和除法,是任何基础计算器的基础。 为了实现这样的功能,开发者可能需要编写一个解析器,将用户输入的中缀...

Global site tag (gtag.js) - Google Analytics