`
leon_a
  • 浏览: 79048 次
  • 性别: Icon_minigender_1
  • 来自: 拜月神教
社区版块
存档分类
最新评论

四则运算的中缀转后缀,逆波兰表达式求值

UP 
阅读更多
首先描述问题
给定一个字符串
example:"4-(4-3*5+(2*4)+100)/10";
要求输出结果"-5.70";结果四舍五入,保留两位小数

首先进行的是括号优先级的处理
	public BigDecimal calculateString(String str) {
		char[] strs = str.toCharArray();
		Stack<String> stack = new Stack<String>();

		for (int i = 0; i < strs.length; i++) {
			String stackStr = String.valueOf(strs[i]);
			stack.push(stackStr);
			if (")".equals(stack.top())) {
				String subStr = null;
				while (!"(".equals(stack.top())) {
					stack.pop();
					if (!"(".equals(stack.top())) {
						subStr = addEnd(subStr, stack.top());
					}
				}
				String pushStr = CalculateReversePolishExpression(subStr);
				stack.pop();
				stack.push(pushStr);
			}

		}
		String resultStr = null;
		while (stack.count != 0) {
			resultStr = CalculateReversePolishExpression(stack.toString());
		}
		BigDecimal result = null;
		if (resultStr != null) {
			result = new BigDecimal(resultStr);
		} else {
			result = BigDecimal.ZERO;
		}
		return result.setScale(2, BigDecimal.ROUND_HALF_UP);
	}

将每个字符逐一进栈,当扫描到")"时,进行出栈操作,直到栈顶元素等于"("
并记录出栈的"("与")"之间的字符串为subStr
然后是对subStr求后缀表达式,并计算结果
也就是这句代码
String pushStr = CalculateReversePolishExpression(subStr);

再把结果进栈
最后stack的内容是去掉括号的一个四则表达式
再进行一次CalculateReversePolishExpression方法,则得到最终结果

中缀转后缀表达式的基本思路
基本思路如下:
用一个链表 List<String> 储存将要生成的后缀表达式
用一个栈 Stack<String> 储存操作符
判断当前节点, 如果是操作数, 直接加入后缀表达式中, 如果是操作符,则比较前一个操作符和当前操作符的优先级,
如果前一个操作符优先级较高,则将前一个操作符加入后缀表达式中,否则将操作符压入操作符栈,如果遇到反括号 ')', 则在操作符栈中反向搜索,直到遇到匹配的正括号为止,将中间的操作符依次加到后缀表达式中。

然后是后缀表达式的计算

遍历储存后缀表达式的链表,将元素依次进栈,当遇到操作符时,连续出栈两个元素,进行运算,再将结果进栈,最后栈内留下的元素就是计算结果

最后再贴出茫茫多的代码
package graph;

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

/**
 * 
 * 应用:逆波兰表达式
 * 
 * @author Leon.Chen
 * 
 */
public class CalculateString {

	public BigDecimal calculateString(String str) {
		char[] strs = str.toCharArray();
		Stack<String> stack = new Stack<String>();

		for (int i = 0; i < strs.length; i++) {
			String stackStr = String.valueOf(strs[i]);
			stack.push(stackStr);
			if (")".equals(stack.top())) {
				String subStr = null;
				while (!"(".equals(stack.top())) {
					stack.pop();
					if (!"(".equals(stack.top())) {
						subStr = addEnd(subStr, stack.top());
					}
				}
				String pushStr = CalculateReversePolishExpression(subStr);
				stack.pop();
				stack.push(pushStr);
			}

		}
		String resultStr = null;
		while (stack.count != 0) {
			resultStr = CalculateReversePolishExpression(stack.toString());
		}
		BigDecimal result = null;
		if (resultStr != null) {
			result = new BigDecimal(resultStr);
		} else {
			result = BigDecimal.ZERO;
		}
		return result.setScale(2, BigDecimal.ROUND_HALF_UP);
	}

	public String[] matcher(String regex, String str) {
		Pattern pattern = Pattern.compile(regex);
		Matcher matcher = pattern.matcher(str);
		List<String> list = new ArrayList<String>();
		while (matcher.find()) {
			list.add(matcher.group());
		}
		String[] result = new String[list.size()];
		return list.toArray(result);
	}

	public List<String> createReversePolishExpression(String subStr) {
		String regex = "\\d+\\.{0,1}\\d*";
		String[] numbers = matcher(regex, subStr);
		String changeStr = subStr.replaceAll(regex, "0").replaceAll("\\-\\-0",
				"-1").replaceAll("\\+\\-0", "+1").replaceAll("\\*\\-0", "*1")
				.replaceAll("\\/\\-0", "/1");
		char[] chars = changeStr.toCharArray();
		int index = 0;
		List<String> list = new ArrayList<String>();
		for (int i = 0; i < chars.length; i++) {
			String str = String.valueOf(chars[i]);
			if ("0".equals(str)) {
				list.add(numbers[index++]);
			} else if ("1".equals(str)) {
				list.add("-" + numbers[index++]);
			} else {
				list.add(str);
			}
		}
		List<String> suffix = new ArrayList<String>();
		Stack<String> operator = new Stack<String>();
		for (int i = 0; i < list.size(); i++) {
			if (!isOperatorType(list.get(i))) {
				suffix.add(list.get(i));
			} else {
				if (operator.count == 0) {
					operator.push(list.get(i));
				} else {
					while (operator.count != 0&&compare(operator.top(), list.get(i)) >= 0) {
						String top = operator.top();
						operator.pop();
						suffix.add(top);
					} 
					operator.push(list.get(i));

				}
			}
		}

		while (operator.count != 0) {
			suffix.add(operator.top());
			operator.pop();
		}
		return suffix;
	}

	public String CalculateReversePolishExpression(String subStr) {
		List<String> suffix = createReversePolishExpression(subStr);
		Stack<Double> stack = new Stack<Double>();
		for (int i = 0; i < suffix.size(); i++) {
			if (!isOperatorType(suffix.get(i))) {
				stack.push(Double.valueOf(suffix.get(i)));
			} else {
				Double current = stack.top();
				stack.pop();
				Double previous = null;
				if (stack.count != 0) {
					previous = stack.top();
					stack.pop();
				} else {
					previous = new Double(0);
				}
				Double result = calculate(suffix.get(i), previous, current);
				stack.push(result);
			}
		}
		return stack.top().toString();
	}

	public String addEnd(String str, String a) {
		StringBuffer buf = new StringBuffer();
		buf.append(a);
		if (str != null) {
			buf.append(str);
		}
		return buf.toString();
	}

	public boolean isOperatorType(String str) {
		if (str.equals("+") || str.equals("-") || str.equals("*")
				|| str.equals("/")) {
			return true;
		}
		return false;
	}

	public int compare(String op1, String op2) {
		Integer iop1 = getOperator(op1);
		Integer iop2 = getOperator(op2);
		return iop1.compareTo(iop2);
	}

	public Integer getOperator(String op) {
		if ("+".equals(op) || "-".equals(op)) {
			return new Integer(0);
		}
		if ("*".equals(op) || "/".equals(op)) {
			return new Integer(1);
		}
		return null;
	}

	public Double calculate(String op, Double previous, Double current) {
		if ("+".equals(op)) {
			return previous + current;
		}
		if ("-".equals(op)) {
			return previous - current;
		}
		if ("*".equals(op)) {
			return previous * current;
		}
		if ("/".equals(op)) {
			return previous / current;
		}
		return null;
	}

	public static void main(String[] args) {
		String[] strs = new String[]{"(5+6)*7","(-1)/(-3)","1/(-3)","-1/7","7+(3*5)-(8+20/2)","4-(4-3*5+(2*4)+100)/10"};
		for(int i=0;i<strs.length;i++){
			BigDecimal result = new CalculateString().calculateString(strs[i]);
			System.out.println(result.toString());
		}
		
	}

}


自己写的stack

package graph;

public class Stack<T> {
	public StackNode<T> stackTop;
	public int count;
	public void push(T info) {
		StackNode<T> node = new StackNode<T>();
		node.info = info;
		node.link = stackTop;
		stackTop = node;
		count++;
	} 
	
	public void pop() {
		if(stackTop == null) {
			System.out.println("null stack");
		} else {
			stackTop = stackTop.link;
			count--;
		}

	}
	
	public boolean isEmpty() {
		return count == 0;
	}
	
	public T top() {
		if(stackTop == null) {
			return null;
		}
		return stackTop.info;
	}
	
	public String toString(){
		Stack<T> other = new Stack<T>();
		while(count != 0){
			T top = top();
			pop();
			other.push(top);
		}
		StringBuffer buf = new StringBuffer();
		while(other.count !=0){
			buf.append(other.top());
			other.pop();
		}
		return buf.toString();
	}

}


stack节点
package graph;

public class StackNode<T> {
	public StackNode<T> link;
	public T info;
}



懒得copy的话下载附件
15
1
分享到:
评论
5 楼 only_xxp 2010-08-19  
学习!!!
4 楼 mingjian01 2010-08-18  
如果我只想将一个中缀表达式完整转为后缀表达式,不想中间有计算结果,程序应该怎样写
3 楼 dogstar 2008-04-25  
龙书一本.
2 楼 leon_a 2008-04-24  
引用
我想说,如果你看了 编译原理,会有更大的收获。
努力!

最近也想往编译原理那方面研究..
有什么好书推荐吗?
1 楼 yananay 2008-04-24  
我想说,如果你看了 编译原理,会有更大的收获。
努力!

相关推荐

    逆波兰表达式求值源代码

    逆波兰表达式求值是计算机科学中的一个重要概念,主要用于避免使用括号来表示运算优先级,从而简化表达式的解析过程。逆波兰表达式,又称后缀表达式,是一种没有括号、无需考虑运算符优先级的数学表达式书写方式。在...

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

    标题 "四则运算求值(中缀转逆波兰式)" 涉及到的是计算机科学中的算法问题,主要集中在表达式求值和转换方法上。逆波兰表示法(Reverse Polish Notation,RPN),也被称为后缀表示法,是一种没有括号的数学表达式...

    四则运算(中缀表达式到后缀表达式)

    本篇将详细介绍从中缀表达式转换为后缀表达式的方法,并探讨如何使用C语言实现四则运算。 中缀表达式是我们日常生活中最常见的表达式形式,例如 \(2 + 3 * 4\)。在这个表达式中,运算符位于操作数之间。然而,这种...

    四则运算关于中缀后缀前缀求值

    2. **后缀表达式**,又称逆波兰表示法,如 "2 3 4 * +”。在这个表示法中,运算符紧跟在其操作数之后。后缀表达式的求值非常简单,只需一个栈即可,因为每个操作数遇到后立即压栈,遇到运算符时,弹出栈顶的两个操作...

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

    后缀表达式(也称为逆波兰表示法或RPN)是一种将操作数放在操作符前面的表达式表示方法。相较于中缀表达式,后缀表达式的优势在于: - **无需考虑操作符的优先级**:在后缀表达式中,操作符总是跟在其操作数之后,...

    四则运算(中缀转后缀)

    然而,在计算机内部处理时,后缀表达式(也称为逆波兰表示法)更为方便,因为它不需要括号来明确运算顺序,如 \(2 3 4 * +\)。本文将详细介绍如何通过C语言实现一个将中缀表达式转换为后缀表达式的算法。 首先,...

    后缀表达式求值(c语言版)

    此外,当前的代码仅支持基本的四则运算,不包括指数、开方等更复杂的数学运算,也不包含错误处理机制,比如除数为零的情况。 总之,该C语言程序提供了一个完整的框架,用于理解和实现后缀表达式的求值过程,特别...

    逆波兰表达式算法_表达式_

    逆波兰表达式(Reverse Polish Notation,RPN)算法是一种基于后缀表示法的计算方法,主要用于解决数学表达式的求值问题。它将运算符放置在操作数之后,避免了括号的使用,使得表达式求值的过程更为直观。在这个算法...

    利用堆栈实现逆波兰表达式 后缀法

    ### 利用堆栈实现逆波兰表达式(后缀法) #### 一、逆波兰表达式简介 逆波兰表达式,又称后缀表达式或后缀记法,是一种没有括号且运算符位于操作数之后的数学表达式书写方式。在计算机科学中,这种表达式被广泛...

    POJ中缀-后缀-四则运算

    人们熟悉的四则运算表达式称为中缀表达式,例如(23+34*45/(5+6+7))。在程序设计语言中,可以利用堆栈的方法把中缀表达式转换成保值的后缀表达式(又称逆波兰表示法),并最终变为计算机可以直接执行的指令,得到...

    基于栈结构的中缀表达式求值实验报告

    在处理这类表达式时,我们通常需要将其转换或直接解析为后缀表达式(也称为逆波兰表示法),因为后缀表达式更适合于简单的栈操作进行求值。然而,通过巧妙地利用栈结构,我们也可以直接对中缀表达式进行求值。本文将...

    获取键盘输入一个中缀表达式,将它转换成后缀表达式,并输出结果

    - **后缀表达式(逆波兰表示法)**:与中缀表达式不同,在后缀表达式中,操作符位于其操作数之后,例如上述的中缀表达式转换为后缀表达式为`3 4 2 * +`。 #### 知识点二:转换算法概述 为了实现题目中的要求,我们...

    用C写的一个算24点代码,使用逆波兰表达式的求值.zip

    在计算24点游戏中,逆波兰表达式可以简化计算过程,避免了中缀表达式(常规的运算符在操作数之间的表达式)转换成后缀表达式(即逆波兰表达式)的步骤。本文将详细讲解如何用C语言实现一个基于逆波兰表达式的24点...

    四则运算表达式的转换并计算结果

    在IT领域,四则运算表达式的转换和计算是计算机科学中的基本问题,特别是在编译原理、数据结构和算法设计中。这里我们主要讨论如何将中缀表达式转换为后缀表达式(也称为逆波兰表示法)以及如何计算后缀表达式的结果...

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

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

    使用逆波兰表达式实现的四则运算解析库、计算器(JavaScript)

    使用逆波兰表达式实现的四则运算解析库、计算器(JavaScript) 功能 任意顺序的四则+-*/运算 支持() 前端后端通用 提供直接计算函数 提供四则运算表达式转逆波兰AST函数 提供语法分析函数(暂时只支持上下两个字符...

Global site tag (gtag.js) - Google Analytics