11 栈与编译器(一):后缀表达式

后缀表达式不需要括号只用双操作数运算符与数字就可以模拟任意因为加括号而得到优先级提升的运算,就是无需括号可以模拟任意运算,例如12+3*等价于(1+2)*3,实际上后缀表达式是对于中缀表达式在计算机中的运算方法

中缀表达式的计算方法:一个operator栈---or,一个operand栈-----od,顺序扫描操作数,如果是数字的话直接入od栈,遇到运算符则判断运算符与or栈的栈顶运算符优先级大小,如果栈顶优先级高,则栈顶的运算符出栈,同时od栈出栈2个操作数进行运算后再存入od栈,继续这个过程直到中缀表达式中遇到的运算符大于or栈中的运算符优先级或者or栈为空,左括号优先级最高,右括号优先级其次,直到遇到左括号把括号弹出为止同等级的根据运算符特性比如-、+,则栈中的表示先出现的,表达式中遇到的表示后出现的,根据左到右的计算特性,则栈中的优先级更高。中间任何一步出问题就是这个中缀表达式有错


中缀到后缀的生成:数字直接输出,运算符通过栈操作,如果栈顶的运算符优先级超过中缀表达式中的运算符优先级,则出栈输出,一直到优先级小于中缀表达式为止,把这个运算符入栈。最后把符号栈中的运算符全部弹出打印就是后缀表达式了。


后缀表达式的计算:数字入栈,遇到符号则弹出2个数字计算结果后将结果如数字栈,继续重复直到表达式结束,数字栈最后只有一个结果就是最后运算结果,不然就是出错


package nuaa.ds;
import java.util.Stack;
import java.util.StringTokenizer;

public class Evaluator {
	private Stack<Integer> opStack;//操作符栈
	private Stack<Long> postfixStack;//前缀表达式栈
	private StringTokenizer str;
	
	//区分不同的运算符
	private static final int EOL = 0;
	private static final int VALUE = 1;
	private static final int OPAREN = 2;
	private static final int CPAREN = 3;
	private static final int EXP = 4;
	private static final int MULT = 5;
	private static final int DIV = 6;
	private static final int PLUS = 7;
	private static final int MINUS = 8;
	
	
	private static Precendence[] precTable = {
		//数字越大优先级越高
		//前一个表示在中缀表达式里面的
		//后一个参数表示在栈里面的
		new Precendence(0,-1),//EOL
		new Precendence(0,0), //VALUE
		new Precendence(100,0),//OPAREN
		new Precendence(0,99),//CPAREN
		new Precendence(6,5),//EXP
		new Precendence(3,4),//MULT
		new Precendence(3,4),//DIV
		new Precendence(1,2),//PLUS
		new Precendence(1,2)//MINUS
	};
	
	public Evaluator(String s){
		opStack = new Stack<Integer>();
		opStack.push(EOL);
		postfixStack = new Stack<Long>();
		str = new StringTokenizer(s,"+*-/^()",true);
	}
	public long getValue(){
		EvalTokenizer tok = new EvalTokenizer(str);
		Token lastToken;
		do{
			lastToken = tok.getToken();
			processToken(lastToken);
		}while(lastToken.getType()!=EOL);
		if(postfixStack.isEmpty()){
			System.err.println("Missing operand!");
			return 0;
		}
		long theResult = postfixStack.pop();
		if(!postfixStack.isEmpty())
			System.err.println("warning:missing operand!");
		return theResult;
	}
	
	private void processToken(Token lastToken){
		int topOp;
		int lastType = lastToken.getType();
		switch(lastType){
		case VALUE:
			postfixStack.push(lastToken.getValue());
			break;
		case CPAREN:
			while((topOp=opStack.peek())!=OPAREN&&topOp!=EOL)
				binaryOp(topOp);
			if(topOp==OPAREN)
				opStack.pop();
			else
				System.err.println("Missing open parenthesis");
			break;
		default:
			while(precTable[lastType].inputSymbol<=
						precTable[topOp=opStack.peek()].topOfStack)
				binaryOp(topOp);
			if(lastType!=EOL)
				opStack.push(lastType);
			break;
				
		}
	}

	private void binaryOp(int topOp){
		if(topOp==OPAREN){
			System.err.println("unbalanced parentheses");
			opStack.pop();
			return;
		}
		long rhs = postfixPop();
		long lhs = postfixPop();
		if(topOp==EXP)
			postfixStack.push((long) Math.pow(lhs,rhs));
		else if(topOp==PLUS)
			postfixStack.push(lhs+rhs);
		else if(topOp==MINUS)
			postfixStack.push(lhs-rhs);
		else if(topOp==MULT)
			postfixStack.push(lhs*rhs);
		else if(topOp==DIV)
			if(rhs!=0)
				postfixStack.push(lhs/rhs);
			else{
				System.err.println("Division by zero");
				postfixStack.push(lhs);
			}
		opStack.pop();
	}
	private long postfixPop(){
		if(postfixStack.isEmpty()){
			System.err.println("Missing operand");
			return 0;
		}
		return postfixStack.pop();
	}
	
	
	private static class Precendence{
		public int inputSymbol;
		public int topOfStack;
		public Precendence(int inSymbol,int topSymbol){
			inputSymbol = inSymbol;
			topOfStack = topSymbol;
		}
	}
	
	private static class Token{
		private int type = EOL;
		private long value = 0;
		
		public Token(){
			this(EOL);
		}
		public Token(int t){
			this(t,0);
		}
		public Token(int t,long v){
			type = t;
			value = v;
		}
		public int getType(){
			return type;
		}
		public long getValue(){
			return value;
		}
	}
	
	private static class EvalTokenizer{
		private StringTokenizer str;
		
		public Token getToken(){
			long theValue;
			if(!str.hasMoreTokens())
				return new Token();
			String s = str.nextToken();
			if(s.equals(" ")) return getToken();
			if(s.equals("^")) return new Token(EXP);
			if(s.equals("/")) return new Token(DIV);
			if(s.equals("*")) return new Token(MULT);
			if(s.equals("(")) return new Token(OPAREN);
			if(s.equals(")")) return new Token(CPAREN);
			if(s.equals("+")) return new Token(PLUS);
			if(s.equals("-")) return new Token(MINUS);
			try{
				theValue = Long.parseLong(s);
			}catch(NumberFormatException e){
				System.err.println("Parse Error");
				return new Token();
			}
			return new Token(VALUE,theValue);
		}
		
		public EvalTokenizer(StringTokenizer is){
			str = is;
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值