Java数据结构与算法——07 逆波兰表达式计算

逆波兰

逆波兰表达式又叫做后缀表达式。逆波兰表示法是波兰逻辑学家J・卢卡西维兹(J・ Lukasewicz)于1929年首先提出的一种表达式的表示方法 。后来,人们就把用这种表示法写出的表达式称作“逆波兰表达式”。逆波兰表达式把运算量写在前面,把算符写在后面。
波兰即前缀表达式,逆波兰即后缀表达式,中缀表达式是最常见的即平时我们所见的表达式:
下面是三种表达式样式
中缀表达式:10+ (5 + 15) × 2 - 6
前缀表达式:- + 10 * + 5 15 2 6
后缀表达式:10 5 15 + 2 * + 6 -
前缀表达式是运算符在前数字在后,后缀表达式数字在前运算符在后

下文主要是写了后缀表达式的三个基本方法,包括字符串转中缀以及中缀转后缀,后缀表达式计算。
将运算符放入一个栈,将数字放入另一个栈中,由于数字栈没有出栈操作,所以可以放入链表中
中缀转后缀思路:
将字符串转换为链表后,遍历链表
1 当遍历值是整数时,直接放入链表中,否则2
2当遍历值是运算符时,如果当前栈为空直接放入 否则3
3遍历值是运算符“(”时直接放入栈中,否则4
4 遍历值是运算符“)”时,执行出栈并加入存放数字的链表中操作,直到出栈预算符为“(”停止,并将“(”出栈
5 遍历值是运算符是其他时,此时需要判断运算符的优先级,如果当前运算符小于或等于栈顶元素时,执行出栈并放入链表中的操作,否则6
6 将运算符压入栈中

将上述步骤遍历操作执行完成后,将栈中剩下的所有运算符出栈存放到链表中,此时的链表即转换好的后缀表达式。
下面是后缀表达式计算思路:
首先创建一个栈用于存放遍历数据
计算过程很简单,首先遍历后缀表达式链表:
1当遍历值是数字时直接压入栈中
2当遍历值是字符时,出栈两个数字,并进行该运算符的运算操作,并将运算结果压入栈中。

当遍历完成后,栈中值即后缀表达式的运算结果

中缀转前缀
这个跟转后缀类似,不同的是它是从右往左遍历也就是链表的倒叙遍历,同转后缀相似的方法,但是它的保存数字的不应该是链表,而是栈,按栈的出栈顺序即是前缀表达式的顺序,后缀用了链表是因为后缀中数据处理结束后,后缀表达式的顺序是(如果用栈的化是栈出栈的反向序列)所以采用了链表存储,这样就不用反序列操作,直接正向遍历即可
下面是中缀转后缀代码实现:

import java.util.ArrayList;
import java.util.Stack;

public class ReversePolishDemo {

	private static int ADD = 0;
	private static int SUB = 0;
	private static int MUL = 1;
	private static int DIV = 1;
	
	public static void main(String[] args) {
		ReversePolishDemo rpd = new ReversePolishDemo();

		String s = "1+((2+3)*4)-5";
		ArrayList<String> infixList = rpd.toinfixList(s);
		ArrayList<String> postfixList = rpd.toPostfixExpressionList(infixList);
		System.out.println(postfixList.toString());
		int result = rpd.colculate(postfixList);
		System.out.println("计算结果是:" + result);
	}
    //字符串转成链表方便处理
	public ArrayList<String> toinfixList(String s) {
		ArrayList<String> infixList = new ArrayList();
		String num = "";
		for (int i = 0; i < s.length(); i++) {

			if (s.charAt(i) < 48 || s.charAt(i) > 57) {//48-57为数字字符对应的asc范围
				if ("" != num) {
					infixList.add(num);
					num = "";
				}
				infixList.add((String)s.substring(i, i+1));
			} else {
				num = num + s.charAt(i);
			}
		}
		if ("" != num) {
			infixList.add(num);
		}
		System.out.println(infixList.toString());
		return infixList;
	}

	public ArrayList<String> toPostfixExpressionList(ArrayList<String> infixList){
		ArrayList<String> postfixList = new ArrayList();
		Stack operators = new Stack();
		
		for(int i = 0;i<infixList.size();i++){
			
			if(infixList.get(i).matches("\\d+")){//如果是数字
				postfixList.add(infixList.get(i));
			}else{
				if(operators.size() == 0){//如果栈为空
					operators.push(infixList.get(i));
				}else if("(".equals(infixList.get(i))){//如果栈为(
					operators.push(infixList.get(i));
				}else if(")".equals(infixList.get(i))){//如果栈为)
					while(!"(".equals(operators.peek())){
						postfixList.add((String) operators.pop());						
					}
					operators.pop();//将(出栈
				}else{
					while(operators.size()>0 && getPriority(infixList.get(i))<= getPriority(operators.peek().toString())){
						postfixList.add((String) operators.pop());		//小于或等于栈中优先级则将操作符存放至链表中
					}
					operators.push(infixList.get(i));
				}
			}			
		}
		while(operators.size()>0){
			postfixList.add((String) operators.pop());	
		}		
		return postfixList;
	}
	
	public int getPriority(String s){
		
		switch(s){
		case "+":
			return ADD;
		case "-":
			return SUB;
		case "*":
			return MUL;
		case "/":
			return DIV;
		}
		return -999;
	}
		
	public int colculate(ArrayList<String> postfixList){
		
		Stack list = new Stack();
		for(String s:postfixList){
			if(s.matches("\\d+")){
				list.push(Integer.valueOf(s));//是数字直接压栈
			}else{
				int num1 = (int) list.pop();//是字符出栈两个数字
				int num2 = (int) list.pop();
				if(s.equals("+")){
					list.push(num1+num2);//运算结果压入栈中
				}else if(s.equals("-")){
					list.push(num2-num1);
				}else if(s.equals("*")){
					list.push(num1*num2);
				}else if(s.equals("/")){
					list.push(num2/num1);
				}
			}
		}
		return (int) list.pop();
		
	}
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值