栈的应用之中缀表达式转后缀

前言


栈的一个广泛应用就是讲中缀表达式转换为后缀表达式。所谓中缀表达式就是我们从小到大所接触的:10+3-6/2+4*5 之类的算数表达式。而后缀表达式又称为逆波兰表达式,

它是由波兰逻辑学家J.Lukasiewicz于1929年提出的。


为什么需要后缀表达式


对于计算机而言,后缀表达式非常方便进行运算。举例来说,对于 "3,5,+," 这样的后缀表达式,其算法如下:
从左至右读取每个字符,若是数字,则入栈;若是操作符,则作用于栈中所弹出的两个数字。

转换算法


那么如何将中缀表达式转换为后缀呢?最简单的步骤如下:

1.按照优先级将整个表达式从里到外加满括号

2.将操作符移动到距离被操作数最近的括号外

3.去掉所有括号后的结果即为后缀表达式。


按照上面的步骤,我们对 10+3-6/2+4*5 进行转换:

第一步:加括号

(((10+3)-(6/2))+(4*5))

第二步:移动操作符


第三步:去掉括号

10 3 + 6 2 /- 4 5 * +

对于人类而言,这是最简单的一种办法了。但是本文的目的是描述中缀转换后缀的程序算法。

算法如下:

初始化一个空栈来保存操作符

循环中缀表达式中每一个字符:

1.当读到操作数时,立即把它放到输出中。操作符不立即输出,而是放进栈中。

2.当遇到左括号时,也将其放到栈中。

3.如果见到一个右括号,那么我们将栈元素弹出,将弹出的符合写出直到我们遇见一个(对应的)左括号,但是
这个左括号,只弹出,不输出。

4.如果我们见到任何其他的符号(“+”,“-”,“*”,“/”,"("),则循环弹出栈顶元素到输出,

直到遇见优先级更低的元素为止(也就是说:如果栈顶符号的优先级大于等于当前符号的优先级,则从栈中弹出元素到输出。)。
有一个例外:除非是在处理一个“)”的时候,否则我们绝不从栈中移走“(”。对于这种操作,“+”的优先级最低,而“(”的优先级
最高。当从栈中弹出元素的工作完成后,我们再将操作符入栈。

5.最后,如果我们读到输入的末尾,我们将栈元素弹出,直到栈变为空栈,将弹出的元素写到输出。


完整的代码如下:

package com.lemon.stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.regex.Pattern;

public class PostfixConverter {
	
	public static void main(String[] args) {
		//String infixExpression="10+3-6/2+4*5";
		String infixExpression="(((10+3)-(6/2))+(4*5))";
		buildPostfixExpression(infixExpression);
	}
	
	public static List<String> buildPostfixExpression(String infixExpression){
		List<String> result=new ArrayList<String>();
		Stack<String> operatorStack=new Stack<String>();
		StringTokenizer strTokenizer = new StringTokenizer(infixExpression, "+-*/()", true);
		String currentEle;
		while (strTokenizer.hasMoreTokens()) {  
			currentEle = strTokenizer.nextToken().trim();
			if(currentEle!=null && !currentEle.equals("")){
				if(isDigital(currentEle)){
					result.add(currentEle);
				}else if(currentEle.equals("(")){
					operatorStack.push(currentEle);
				}else if(currentEle.equals(")")){
					while(!operatorStack.isEmpty() && !operatorStack.peek().equals("(")){
						result.add(operatorStack.pop());
					}
					operatorStack.pop();
				}else if(currentEle.equals("+")||currentEle.equals("-")||
						currentEle.equals("*")||currentEle.equals("/")||
						currentEle.equals("(")||currentEle.equals(")")){
					while(!operatorStack.isEmpty() 
							&&
							(!currentEle.equals(")") && !operatorStack.peek().equals("("))&&
							getPriority(operatorStack.peek())>=getPriority(currentEle)){
						result.add(operatorStack.pop());
					}
					operatorStack.push(currentEle);
				}
			}
			
		}
		while(!operatorStack.isEmpty()){
			result.add(operatorStack.pop());
		}
		System.out.println(result.toString());
		return result;
	}
	
	public static int getPriority(String operator){
		if(operator.equals("+")||operator.equals("-")){
			return 1;
		}else if(operator.equals("*")||operator.equals("/")){
			return 2;
		}else if(operator.equals("(")){
			return 3;
		}
		return 0;
	}
	
	/** 
	 * 判断字符串是否是数字类型 
	 * @param str 
	 * @return true:数字;false:非数字
	 */  
	public static boolean isDigital(String str) {  
		String numRegex = "^\\d+(\\.\\d+)?$"; 
		return Pattern.matches(numRegex, str);  
	}  
}





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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值