JAVA数据结构学习实例--利用栈解析算术表达式

这几天复习数据结构,

复习到栈那一章,其中有一个使用栈来解析算术表达式的实例,但是只能解析由一位数字组成的表达式, 如过是 2*5+18 这样出现两位及以上的操作数就不能解析了。

于是重写了一个比较完善的算术表达式解析程序:

以下是完整的代码 带注释应该挺详细的了:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Stack;

/**
 * 
 * @author Mr.Free
 * Compute Arithmetic Expression using stack ds.
 * input arithmetic expression like:  3*(15+9)/9, compute the result
 * using stack 
 * Steps:   1. tanslate an infix expression into a postfix expression
 * 			2. parsing it.
 */
public class StackTest {
	public static Stack<String> operator = new Stack<String>(); //操作符号栈,用来存放操作符号,将会在中缀转后缀表达式程序中使用
	public static Stack<String> operation =  new Stack<String>();//

	/**
	 * 这段是将中缀表达式分解成字符串数组,这样就能操作多位操作数了  
	 * 
	 */
	public static String[] splitIntoArray(String expStr) {  
		char c;
		ArrayList<String> opList = new ArrayList<String>();
		String temp;
		Stack<String> s = new Stack<String>();
		for(int i = 0; i< expStr.length(); i++) {
			temp = "";
			c = expStr.charAt(i);
			if(c <= '9' && c >= '0') {
				s.push(String.valueOf(c));
			} else {
				while(!s.isEmpty())
					 {  
					 	temp += String.valueOf(s.pop());
					 }
					 //add operand,因为是栈,弹出多位操作数后需要将它倒序输出
				if(!temp.equals("")) opList.add(new StringBuffer(temp).reverse().toString()); 
				opList.add(String.valueOf(c));  // add operator
			}
		}
		temp ="";
		
		//add the remaining operator
		while(!s.isEmpty()) {
		 	temp += String.valueOf(s.pop());
		}
		if(temp!="") opList.add(temp);
		
		String []str;
		str = opList.toArray(new String[opList.size()]);
		return str;
	}
	
	/**
	 * 中缀表达式转后缀表达式,很好的利用了栈的先进后出的特性
	 * 返回后缀表达式
	 */
	public static String[] infix2Postfix(String []str) {
	
//		String []postfix = new String[str.length];

		ArrayList<String> postList = new ArrayList<String>();
		for(int i = 0; i<str.length; i++) {
			if(!str[i].matches("[+\\-\\(\\)\\*/]")) {
				postList.add(str[i]);
			} else {
				//operator length is just one, so can use switch statement
				char oper = str[i].charAt(0);
				String rs;
				switch(oper) {
				case '+': 
				case '-':
					rs = getOper(String.valueOf(oper), 1); // 1 use to presents the precedence,1代表优先级,+- 是1
					if(rs != "") postList.add(rs); ;
					break;  
				case '*':
				case '/':
					rs = getOper(String.valueOf(oper), 2);  //2 * /乘除是2
					if(rs != "") postList.add(rs) ;
					break;
				case '(':                           //括号是最高优先级,不需要放getOper里面判断了
				operator.push("(");
					break;
				case ')':
					postList.add(operator.pop());
					operator.pop(); // delete "("
					break;
				}
			}
		}
		while(!operator.isEmpty()) postList.add(operator.pop()); //return the remaining operator
		
		String []postfix;
		postfix = postList.toArray(new String[postList.size()]);
		return postfix;
	}
	/**
	 * 用于在中缀转后缀过程中取+-* /符号
	 * 取操作符号时总是比较新的操作符和旧操作符,新操作符优先级别小于等于旧操作符就返回旧操作符,压入新操作符,否则
	 * 压入新操作符返回nothing
	 * 例:5+6+7 按人脑计算步骤我们总是看到5+6后的+号 我们才开始计算5+6。 此处同理
	 */
	public static String getOper(String oper, int precNew) {
		String oldTop; // old operator
		if(operator.isEmpty()) {
			operator.push(oper);
			return ""; //return nothing
		} else {
			oldTop = operator.peek();
			int precOld = 0;
			if(oldTop.matches("\\(")) {
				operator.push(oper);
				return "";
			} else {
				if (oldTop.matches("[+-]")) {
					precOld = 1;
				} else {
					precOld = 2;
				}
				if(precNew <= precOld) {
					String operNew = operator.pop();
					operator.push(oper);
					return operNew;  // return operator
				} else {
					operator.push(oper);   // stor new operator
					return "";  // retunr nothing
				}
			}
		}
	}
    /**
     * 计算后缀表达式,这步挺简单的,后缀表达式可以从左到右按顺序计算(这就是为什么我们要花力气将表达式转换为后缀表达式)
     * 遇到操作符便取前两个操作数计算。操作数存放在operation栈里。。其实应该叫operand 栈贴切一些。。懒得改了将就吧。
     * 
     */
	public static double parsePostfix(String []str) {
		double result = 0;
		char c;
		
		for(int i = 0; i< str.length; i++) {
			if(!str[i].matches("[+\\-\\*/]")) {
				operation.push(str[i]); // push operands
			} else {
				c = str[i].charAt(0);
				switch(c) {
				case '+':
					result = Double.parseDouble(operation.pop()) 
								+ Double.parseDouble(operation.pop());
					operation.push(String.valueOf(result));
					break;
				case '-'://注意减法后取出的是被减数,先出栈的是减数,同理在除法部分也有体现,先出栈的是除数
				//后出栈的是被除数。
					result = -Double.parseDouble(operation.pop()) 
								+ Double.parseDouble(operation.pop());
					operation.push(String.valueOf(result));
					break;
				case '*':
					result = Double.parseDouble(operation.pop()) 
					* Double.parseDouble(operation.pop());
					operation.push(String.valueOf(result));
					break;
				case '/':
					result = 1 / Double.parseDouble(operation.pop()) 
					* Double.parseDouble(operation.pop());
					operation.push(String.valueOf(result));
					break;
				}
			}
		}
		
		return result;	
	}
	//测试程序。。
	public static void main (String []args) {
		String expression = getInput();
		String []splitOp = splitIntoArray(expression);
		String []rs = infix2Postfix(splitOp);
		for(String r: rs) {
			System.out.print(r);
		}
		
		System.out.println("\n" + expression +"=" + parsePostfix(rs));
	}

	private static String getInput() {
		// TODO Auto-generated method stub
		System.out.println("Please input an expression:");
		BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
		try {
			return bf.readLine();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			try {
				bf.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		return null;
	}
}


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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值