`
chengpan
  • 浏览: 44287 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

混合运算 后缀表达式算法实现

阅读更多

因为要用到四则混合运算,写了一个工具类,是基于后缀表达式的实现

 

package com.eden.door.util;

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;



/**
 * 处理四则混合运算 , 支持负数+,-,*,/,%,^,括号
 * @author Eden
 *
 */
public class Calculator {
	private static Calculator instance = new Calculator() ;
	
	private String operators = "+-*/%^()#" ;
	
	//运算符栈外优先级
	private Map<String, Integer> icp = null ;
	//运算符栈内优先级
	private Map<String, Integer> isp = null ;
	
	public static Calculator newInstance(){
		return instance ;
	}
	
	public Calculator(){
		icp = new HashMap<String, Integer>();
		isp = new HashMap<String, Integer>();
		
		icp.put("#", 0) ;
		icp.put(")", 1) ;
		icp.put("+", 2) ;
		icp.put("-", 2) ;
		icp.put("*", 4) ;
		icp.put("/", 4) ;
		icp.put("%", 4) ;
		icp.put("^", 6) ;
		icp.put("(", 8) ;
		
		isp.put("#", 0) ;
		isp.put("(", 1) ;
		isp.put("+", 3) ;
		isp.put("-", 3) ;
		isp.put("*", 5) ;
		isp.put("/", 5) ;
		isp.put("%", 5) ;
		isp.put("^", 7) ;
		isp.put(")", 8) ;
	}
	/**
	 * 格式化表达式  ,有符号的,在前面加上0
	 * 例如(-2) + 3 格式化之后 (0-2) + 3
	 * @param exp 
	 * @return
	 */
	protected String formatExp(String exp) {
		
		String sign = "+-" ;
		StringBuilder sbExp = new StringBuilder(exp.trim().replace(" ", "")) ;
		
		if(sign.contains(sbExp.subSequence(0, 1))){
			sbExp.insert(0, "0") ;
		}
		for(int i = 0; i < sbExp.length(); i++) {
			if(sbExp.charAt(i) == '('){
				if(sign.contains(String.valueOf(sbExp.charAt(i+1)))){
					sbExp.insert(i+1, "0") ;
				}
			}
		}
		return sbExp.toString() ;
	}
	
	/**
	 * 判断字符是否为运算符
	 * @param c
	 * @return
	 */
	protected boolean isOperator(char c) {
		if(operators.contains(String.valueOf(c)))
			return true ;
		return false ;
	}
	protected boolean isOperator(String s){
		if(operators.contains(s))
			return true ;
		return false ;
	}
	

	
	/**
	 * 优先级的比较 
	 * @param currOp 当前运算符
	 * @param preOp 栈顶运算符
	 * @return 
	 * 当前运算符 > 栈顶运算符 返回 -1  
	 * 当前运算符 = 栈顶运算符 返回 0  
	 * 当前运算符 < 栈顶运算符 返回1 
	 */
	protected int opComp(String currOp , String preOp) {
		
		int currPriority = icp.get(currOp) ;
		int prePriority = isp.get(preOp) ;
		
		if( prePriority > currPriority )
			return 1 ;
		else if ( prePriority == currPriority ) {
			return 0;
		} else
			return -1 ;
	}
	
	/**
	 * 中缀表达式转换为后缀表达式
	 * @param infix
	 * @return
	 */
	protected List<String> infix2Postfix(String infix){
		List<String> postfixList = new ArrayList<String>() ;
		
		List<String> infixList = infixStr2List(infix) ;
		Deque<String> opStack = new ArrayDeque<String>() ;
		
		
		String str = "" ;
		for(int i = 0 ; i < infixList.size() ; i++){
			str = infixList.get(i) ;
			
			if(isOperator(str)){
				
				if( "(".equals(str) ){
					opStack.push(str) ;
				} 
				else if( ")".equals(str) ){
					while(!"(".equals(opStack.peek()) ){
						postfixList.add(opStack.pop()) ;
					}
					opStack.pop() ;
				}
				
				else if(opStack.peek() == null){
					opStack.push(str) ;
				} else {
					//如果栈顶运算符优先级比当前运算符优先级低将栈顶运算符弹邮放到后缀表达式中
					while( opStack.peek()!= null && opComp(str , opStack.peek()) >= 0 ){
						postfixList.add(opStack.pop()) ;
					}
					if(opStack.peek() == null){
						opStack.push(str) ;
					} 
					//如果栈顶运算符优先级比当前运算符优先级高压到后缀表达式中
					else if ( opComp(str , opStack.peek()) == -1 ) {
						opStack.push(str) ;
					}
				}
			} else {
				postfixList.add(str) ;
			}
		}
		//最后把栈中的运算符加到后缀表达式中
		while(opStack.peek() != null){
			postfixList.add(opStack.pop()) ;
		}
		
		return postfixList ;
	}
	
	/**
	 * 将中缀表达式字符串转换为中缀List
	 * @param infix
	 * @return
	 */
	protected List<String> infixStr2List(String infix){
		List<String> infixList = new ArrayList<String>() ;
		int start = 0 ;
		for(int i = 0 ; i < infix.length() ; i++){
			if(isOperator(infix.charAt(i)) ){
				if(i - start > 0){
					//截取两个运算 符之间的数字
					infixList.add(infix.substring(start , i) ) ;
				}
				start = i+1 ;
				//将运算符放到中缀表达式中
				infixList.add(infix.substring(i, i+1)) ;
			}
		}
		
		//如果最 后一位为数字
		if(start<infix.length()){
			infixList.add(infix.substring(start)) ;
		}
		return infixList ;
	}
	/**
	 * 计算运算表达式
	 * @param expression
	 * @return
	 */
	public double calculate(String expression) {
		//格式化运算式
		String infix = this.formatExp(expression) ;
		//求出中缀表达式
		List<String> infixList = infixStr2List(infix) ; 
		//得出后缀表达式
		List<String> postfixList = infix2Postfix(infix) ;
		
		System.out.println(infix) ;
		System.out.println(infixList) ;
		System.out.println(postfixList) ;
		
		//计算后缀表达式
		double r = computePostfix(postfixList) ;
		
		return r ;
	}
	
	/**
	 * 对后缀表达式求值
	 * @param postfixList
	 * @return
	 */
	protected double computePostfix(List<String> postfixList) {
		Deque<Double> rsStack = new ArrayDeque<Double>() ;
		
		double r = 0 ;
		for(String item : postfixList) {
			if(!isOperator(item)){
				rsStack.push(Double.parseDouble(item)) ;
			} else {
				double num1 = rsStack.pop() ;
				double num2 = rsStack.pop() ;
				
				if("+".equals(item)){
					r = num2 + num1 ;
				} else if("-".equals(item)){
					r = num2 - num1 ;
				} else if("*".equals(item)){
					r = num2 * num1 ;
				} else if("/".equals(item)){
					r = num2 / num1 ;
				} else if("%".equals(item)){
					r = num2 % num1 ;
				} else if("^".equals(item)){
					r = Math.pow(num2, num1) ;
				}
				
				rsStack.push(r) ;
			}
		}
		
		return rsStack.pop() ;
	}
	
	//测试
	public static void main(String[] args){
		
		String exp = "1/(0.3243e3) * ((-20 + 28) + (2 + 2))" ;
		
//		System.out.println( System.currentTimeMillis()) ;
		System.out.println(Calculator.newInstance().calculate(exp) ) ;
//		System.out.println( System.currentTimeMillis() ) ;
	}
}
 

        for(String item : postfixList) {
            if(!isOperator(item)){
                rsStack.push(Double.parseDouble(item)) ;
            } else {
                double num1 = rsStack.pop() ;
                double num2 = rsStack.pop() ;
               
                if("+".equals(item)){
                    r = num2 + num1 ;
                } else if("-".equals(item)){
                    r = num2 - num1 ;
                } else if("*".equals(item)){
                    r = num2 * num1 ;
                } else if("/".equals(item)){
                    r = num2 / num1 ;
                } else if("%".equals(item)){
                    r = num2 % num1 ;
                } else if("^".equals(item)){
                    r = Math.pow(num2, num1) ;
                }
               
                rsStack.push(r) ;
            }
        }
       
        return rsStack.pop() ;
    }
   
    //测试
    public static void main(String[] args){
       
        String exp = "1/(0.3243e3) * ((-20 + 28) + (2 + 2))" ;
       
//        System.out.println( System.currentTimeMillis()) ;
        System.out.println(Calculator.newInstance().calculate(exp) ) ;
//        System.out.println( System.currentTimeMillis() ) ;
    }
}

分享到:
评论

相关推荐

    C++四则混合运算表达式求值算法

    ### C++四则混合运算表达式求值算法详解 #### 引言 四则运算表达式通常由操作数、操作符以及括号组成。其中,操作数可以是任意实数,而操作符主要包括加(+)、减(-)、乘(*)及除(/)。在计算机科学中,有效地...

    stack实现运算表达式(C++实现)

    总之,通过使用C++的`std::stack`容器,我们可以有效地解析和计算运算表达式,这个过程涉及到词法分析、运算符优先级处理以及后缀表达式的计算。这个示例提供了一个基础的框架,对于理解和实现更复杂的表达式解析...

    四则混合运算表达式处理

    ### 四则混合运算表达式处理 ...通过以上分析可以看出,四则混合运算表达式的处理不仅涉及到数据结构的设计和实现,还涉及到算法的应用和优化。这个程序为理解和实现逆波兰表示法下的四则运算提供了一个良好的示例。

    数学表达式的求值算法实现(加减乘除及平方的混合运算)

    2. **构建运算栈**:在后缀表达式中,我们使用一个栈来存储操作数和运算符。遍历后缀表达式,遇到数字时压入栈,遇到运算符时取出栈顶的两个操作数进行运算,结果再压回栈。 3. **运算符优先级处理**:对于加减乘除...

    Java综合程序设计——计算器(实现运算符优先级的四则混合运算)

    在本项目中,"Java综合程序设计——计算器(实现运算符优先级的四则混合运算)"是一个典型的软件开发任务,旨在实现一个功能丰富的计算器,包括基础的四则运算以及更复杂的数学操作如对数和平方根。这个计算器的关键...

    四则混合运算的算法

    此算法用于四则运算,没有对异常进行处理。 输入形式请如下: A+(B+C)*D= ((B+C)*D+(A+F)/E)+G/H+W= 记得输入等号,本人没有考虑回车的情况,请自行修改。 文件arithmeic主要用于将中缀表达式转为后缀表达式。 cal_...

    栈与四则混合运算的实现

    4. **后缀表达式(逆波兰表示法)**:这是使用栈计算四则混合运算的一种常见方法。首先将表达式转换为后缀表达式,然后逐个从左到右读取元素,如果是数字,则压入栈;如果是运算符,就弹出栈顶的两个元素进行运算,...

    四则混合运算计算器

    在MFC中,四则混合运算计算器的实现涉及以下几个关键知识点: 1. **用户界面设计**:VS2008中的MFC提供了一套强大的资源编辑器,可以用于创建GUI(图形用户界面)。计算器通常包含数字按钮、运算符按钮、清除按钮、...

    表达式求值,加减乘除混合运算

    在本主题中,我们将深入探讨如何使用栈数据结构处理加减乘除四则混合运算,包括处理括号。栈是一种具有“后进先出”(LIFO)特性的数据结构,非常适合于解决此类问题。 首先,我们需要理解表达式的求值过程。对于...

    数据结构大作业C++实现简单的计算器——算术表达式计算(包含实验报告)

    利用运算符优先关系,实现对算术四则混合运算表达式的求值。 【测试数据】 (1)能够判断表达式中的括号是否匹配,测试的表达式中括号不匹配,可以重新输入。 (2)能够处理多位整数以及浮点数。 (3)具体测试数据...

    C++混合运算计算器~~~!!!

    总的来说,构建一个C++混合运算计算器需要理解类和对象的概念,熟悉操作符重载,掌握后缀表达式的计算方法,以及如何处理分数计算。这个项目不仅可以提升编程技巧,也是对C++基础知识的一次全面实践。通过不断调试和...

    c#实现四则混合运算

    总结来说,C#实现四则混合运算的关键步骤包括词法分析、语法分析(构建二叉树)、后缀表达式转换以及使用栈进行计算。这些步骤涉及了编译原理中的基本概念,同时展示了C#语言如何处理数据结构和算法问题。在实际开发...

    加减乘除四则混合运算计算器-java

    这种算法称为后缀表达式(Postfix Expression)或逆波兰表示法,可以简化运算符优先级的处理。 对于错误处理,我们需要考虑用户可能输入的非法运算,比如除以零或者未完成的表达式。我们可以设定异常处理机制,当...

    利用栈求表达式的值

    总之,利用栈求表达式的值是一种高效且实用的方法,它利用了栈的特性来简化复杂的运算逻辑,对于理解和实现计算算法具有重要意义。通过学习和实践这一方法,我们可以更好地掌握数据结构和算法在实际问题中的应用。

    数据结构实验二_算术表达式求值实验报告.doc

    本实验报告的主要内容是设计一个程序,演示通过将数学表达式字符串转化为后缀表达式,并通过后缀表达式结合栈的应用实现对算术表达式进行四则混合运算。下面是实验报告的详细内容: 一、问题描述 算术表达式求值是...

    vs2008C#写的四则混合运算的计算器

    逆波兰表达式(RPN),又称后缀表达式,是一种方便进行计算的表示方法。在RPN中,运算符位于它们的操作数之后,这样就无需括号来明确运算顺序。例如,常规表达式"2 + 3 * 4"在RPN中变为"2 3 4 *"。RPN的优点在于,它...

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

    这里我们讨论的是一款用C#语言编写的能进行四则混合运算的计算器,尤其支持含有括号的运算式。四则混合运算包括加法(+)、减法(-)、乘法(*)和除法(/),而括号的引入则使得运算的顺序和优先级得以明确。 首先...

    用VC6.0写的可进行四则混合运算的计算器

    总结来说,用VC6.0实现四则混合运算的计算器,不仅是一次编程实践,也是对基础理论知识的巩固,它涉及到了C++编程语言、图形用户界面设计、数据结构与算法等多个方面,对于提升编程能力大有裨益。

    C++ 四则运算混合计算器源码

    对于混合运算,我们需要考虑运算符的优先级和括号的使用。C++遵循PEMDAS(括号、指数、乘除、加减)规则,即先处理括号内的运算,然后是指数,接着是乘法和除法(从左到右),最后是加法和减法(同样从左到右)。...

    中序表达式计算(四则混合).zip_中序表达式_表达式计算

    在编程领域,中序表达式计算...总结起来,中序表达式计算涉及了数据结构(栈)、算法(中序转后序、后缀表达式计算)以及四则混合运算的规则。通过理解这些知识点,我们可以编写出能正确处理各种中序表达式的计算程序。

Global site tag (gtag.js) - Google Analytics