关于java实现 计算四则表达式的 问题

u013259130 2014-04-10 09:38:39
用java来实现计算表达式的功能。

输入: 51+54*(3+2)
输出:321

程序读取用户的输入,然后给出表达式的结果。要求用栈来实现这个功能。

我现在的想法是,用一个operandStack栈来存储操作数,operatorStack来存储运算符。从左往右扫描表达式,把操作数和运算符分别压入栈中,然后通过一定的算法来实现求解表达式的解。

现在我的问题就是求思路,怎样来实现这个算法。
1:一般来说,提取到一个运算符,就会提取两个操作数进行计算,但这要考虑到运算符的优先级,乘除的优先级高于加减,这个需要怎么处理。
2:遇到括号会改变优先级,这个又来如何处理。

请大神能够给出较为详细的步骤,同时如果能够再解释一下为什么这样计算的步骤就更好了。
...全文
372 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
冰思雨 2014-04-17
  • 打赏
  • 举报
回复
这个应该是编译原理里面的内容。以前帮别人写过一个代数运算器,比楼主这个要复杂得多,但是,原理基本是一致的。 楼主可以看看我的博客 从C语言转换过来的Java版,字符串代数运算器 或许能够得到启发。
sunbo624 2014-04-17
  • 打赏
  • 举报
回复
引用 9 楼 Inhibitory 的回复:
[quote=引用 8 楼 sunbo624 的回复:] 先分词 把运算符和数字分开 然后用一个栈 把中缀表达式转成后缀表达式 然后用一个栈 计算
分词很简单:
    private List<String> expressionTokens(String expression) {
        // 1. 在操作符的两边加上空格, 便于分解
        // 2. 用空格分解成list
        return Arrays.asList(expression.replaceAll("([/\\+\\-\\*\\(\\)])", " $1 ").trim().split("\\s+"));
    }
[/quote] 显然这样不合理 1.为什么要加空格 你不能用你的规范去控制调用者 2.显然不该用正则 2.1 你正则写的不对 一次分不干净 因为你没考虑负数 2.2 正则分完了 但是失去了对源字符串校验的功能 这个步骤应该伴随着分词 不该分两步 影响性能
u011050058 2014-04-17
  • 打赏
  • 举报
回复
package com.csb.tree;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Scanner;
import java.util.Stack;

/**
 * 
 * @author csb
 * 逆波兰表达式(后缀表达式) 是一种由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。
 */
public class ReversePolishNotation {
	static HashMap<String,Integer> operatorLevel ;
	static {
		operatorLevel = new HashMap<String,Integer>();
		operatorLevel.put("(", 5);
		operatorLevel.put(")", 5);
		operatorLevel.put("*", 4);
		operatorLevel.put("/", 4);
		operatorLevel.put("+", 3);
		operatorLevel.put("-", 3);
	}
	/**
	 * 传入的是一个数组(包含操作符【+,-,*,/】和操作数【整数】)
	 * @return int 
	 * jdk1.7+
	 */
	public static int eval(String[] tokens){
		int result = 0;
		String operators = "+-*/";
		Stack<String> stack = new Stack<String>();
		for(String t : tokens)
		{
			if(!operators.contains(t))
			{
				stack.push(t);
			}else
			{
				int a = Integer.valueOf(stack.pop());
				int b = Integer.valueOf(stack.pop());
				switch(t)
				{
				case "+":
					stack.push(String.valueOf(a+b));
					break;
				case "-":
					stack.push(String.valueOf(b-a));
					break;
				case "*":
					stack.push(String.valueOf(a*b));
					break;
				case "/":
					stack.push(String.valueOf(b/a));
					break;
				}
			}
		}
		result = Integer.valueOf(stack.pop());
		return result;
	}
	
	/**
	 * jdk all
	 * @return
	 */
	public static int evaluate(String[] tokens)
	{
		int result = 0;
		String operators = "+-*/";
		Stack<String> stack = new Stack<String>();
		for(String t : tokens)
		{
			if(!operators.contains(t))
			{
				stack.push(t);
			}else
			{
				int a = Integer.valueOf(stack.pop());
				int b = Integer.valueOf(stack.pop());
				int index = operators.indexOf(t);
				switch(index)
				{
				case 0:
					stack.push(String.valueOf(a+b));
					break;
				case 1:
					stack.push(String.valueOf(b-a));
					break;
				case 2:
					stack.push(String.valueOf(a*b));
					break;
				case 3:
					stack.push(String.valueOf(b/a));
					break;
				}
			}
		}
		result = Integer.valueOf(stack.pop());
		return result;
	}
	
	public static String[]  toReversePolishNotation(String input){
		input = input.replaceAll(" ", "").replaceAll("=", "");//去除表达式中的空格和=号
		String[] newArr = input.replaceAll("([/\\+\\-\\*\\/\\(\\)])"," $1 ").trim().replaceAll("  ", " ").split(" "); //先把字符串中的操作符左右加空格,再去除最左和最后的空格,在把由于括号和运算符连在一起造成2个空格换成一个空格,最后根据空格分开
		ArrayList<String> output = new ArrayList<String>();
		Stack<String> stack = new Stack<String>();
		for(String t:newArr)
		{
			switch(t)
			{
			case "(":
				stack.push(t);
				break;
			case "+":
				if(!stack.empty()&&operatorLevel.get(stack.peek())>=operatorLevel.get(t))
				{
					do{
						if(stack.peek().equals("("))
						{
							break;
						}
						output.add(stack.pop());
						
					}while(!stack.empty()&&operatorLevel.get(stack.peek())>=operatorLevel.get(t));
					stack.push(t);
				}else
				{
					stack.push(t);
				}
				break;
			case "-":
				if(!stack.empty()&&operatorLevel.get(stack.peek())>=operatorLevel.get(t))
				{
					do{
						if(stack.peek().equals("("))
						{
							break;
						}
						output.add(stack.pop());
					}while(!stack.empty()&&operatorLevel.get(stack.peek())>=operatorLevel.get(t));
					stack.push(t);
				}else
				{
					stack.push(t);
				}
				break;
			case "*":
				if(!stack.empty()&&operatorLevel.get(stack.peek())>=operatorLevel.get(t))
				{
					do{
						if(stack.peek().equals("("))
						{
							break;
						}
						output.add(stack.pop());
					}while(!stack.empty()&&operatorLevel.get(stack.peek())>=operatorLevel.get(t));
					stack.push(t);
				}else
				{
					stack.push(t);
				}
				break;
			case "/":
				if(!stack.empty()&&operatorLevel.get(stack.peek())>=operatorLevel.get(t))
				{
					do{
						if(stack.peek().equals("("))
						{
							break;
						}
						output.add(stack.pop());
					}while(!stack.empty()&&operatorLevel.get(stack.peek())>=operatorLevel.get(t));
					stack.push(t);
				}else
				{
					stack.push(t);
				}
				break;
			case ")":
				while(!stack.isEmpty()&&!stack.peek().equals("("))
				{
					output.add(stack.pop());
				}
				stack.pop();
				break;
				default:
					output.add(t);
					break;				
			}
			System.out.println(t);
			System.out.println("stack="+stack);
			System.out.println("output="+output);
		}
		while(!stack.isEmpty())
		{
			output.add(stack.pop());
		}
		String[] result = new String[output.size()];
		output.toArray(result);
		return result;
	}
	
	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		System.out.println("请输入算式");
		Scanner s = new Scanner(System.in); //输入表达式
		String input = s.nextLine();
		String[] tookes = toReversePolishNotation(input);
		System.out.println(String.valueOf(evaluate(tookes)));
	}

}
Inhibitory 2014-04-16
  • 打赏
  • 举报
回复
引用 8 楼 sunbo624 的回复:
先分词 把运算符和数字分开 然后用一个栈 把中缀表达式转成后缀表达式 然后用一个栈 计算
分词很简单:
    private List<String> expressionTokens(String expression) {
        // 1. 在操作符的两边加上空格, 便于分解
        // 2. 用空格分解成list
        return Arrays.asList(expression.replaceAll("([/\\+\\-\\*\\(\\)])", " $1 ").trim().split("\\s+"));
    }
sunbo624 2014-04-14
  • 打赏
  • 举报
回复
先分词 把运算符和数字分开 然后用一个栈 把中缀表达式转成后缀表达式 然后用一个栈 计算
alan19931103 2014-04-14
  • 打赏
  • 举报
回复
没太理解楼主的要求,但是如果是需要解析一个数学表达式的字符串的话可以了解一下设计模式的解释器模式。 还可以用一些第三方解析工具包,比如Expression4J、jep、jbcParser、Symja、MESP
水晶之夜2013 2014-04-11
  • 打赏
  • 举报
回复
引用 1 楼 akon405 的回复:
好像是编译原理的知识
......数据结构的题。用栈来实现。。。
Inhibitory 2014-04-11
  • 打赏
  • 举报
回复
你的这个做法需要准备一个算符优先表,麻烦的也在这里。 如果先把表达式转变成逆波兰式,然后在用一个栈会简单一些。 逆波兰式可以用算符优先表,也可以用更简单的,直接就给每个运算符权值。
sjlzcj 2014-04-10
  • 打赏
  • 举报
回复
算符优先
巫巫巫 2014-04-10
  • 打赏
  • 举报
回复
好像是编译原理的知识

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧