利用栈实现中缀转化成后缀表达式并求值

后缀表达式

假设我们计算一个表达式:42+5+67=,他的计算顺序可以是将42的值存为A1,然后将A1和5相加,在将结果存入A1,然后在将67的值存为A2,最后将A1和A2相加,并将结果放入A1。那我们可以将这种操作顺序写成这样:4 25+6 7+。这个写法就叫后缀(postfix)或逆波兰(reverse polish)写法。这种写法的在计算机中可以用一个栈来实现:遇见一个数,把他放到栈中,在遇到一个运算符时,该运算符作用于从该栈弹出的两个数上,在将结果放入到栈中,例如:6 5 2 3 + 8 * + 3 + *

1.将6 5 2 3放入栈中
利用栈实现中缀转化成后缀表达式并求值_第1张图片
2.下面读到一个+号,所以3和2从栈中弹出,把他们的和5压入栈中
利用栈实现中缀转化成后缀表达式并求值_第2张图片
3.接着8进栈
利用栈实现中缀转化成后缀表达式并求值_第3张图片
4.然后 * 进栈,8和5弹出,40进栈
利用栈实现中缀转化成后缀表达式并求值_第4张图片
中间省略一些步骤,最终得出正确结果。这样下来计算一个后缀表达式花费的时间是O(N)。而且使用后缀表达式不需要知道任何优先级规则。

中缀到后缀的转化

下面说明如何利用栈将一个标准的中缀表达式转化为后缀表达式
表达式:a+bc+(de+f)g转化后是abc*+def+g+
当读到一个数字的时候,放到输出中,操作符放入到一个栈中。具体的操作下面通过图说明:
1.首先,a被读入,放到输出中,然后 + 被读入,放到栈中,接下来,b读入放到输出中
利用栈实现中缀转化成后缀表达式并求值_第5张图片
2.接着读入,+ 没有 * 优先级高,+ 不输出, 进栈,c读入放到输出
利用栈实现中缀转化成后缀表达式并求值_第6张图片
3.接下来,+ 读入,+ 比 * 优先级底,所以将 * 从栈弹出到输出,弹出剩下的 +,该运算符和刚刚遇到的 + 优先级一样,然后将刚刚遇到的 + 压入栈中
利用栈实现中缀转化成后缀表达式并求值_第7张图片
4.接下里,最高优先级的 ( 读入,压入栈中,d 读入到输出中
利用栈实现中缀转化成后缀表达式并求值_第8张图片
5.继续,* 读入,压入栈中,e读入到输出
利用栈实现中缀转化成后缀表达式并求值_第9张图片
6.接续,+ 读入,比栈中的 * 优先级低,所以 * 出栈到输出,+ 压入栈中,f读入到输出
利用栈实现中缀转化成后缀表达式并求值_第10张图片
7.接下来,) 读入,因此将栈中的元素知道 ( 弹出
利用栈实现中缀转化成后缀表达式并求值_第11张图片
8.然后又读入 * ,压入栈中,g读入到输出
利用栈实现中缀转化成后缀表达式并求值_第12张图片
9.现在读入空,所以将栈中的符号全部弹出,知道变为空栈
利用栈实现中缀转化成后缀表达式并求值_第13张图片
这种转化只需要O(N)的时间并经过一趟输入后工作完成,可以通过制定加减法又相同的优先级以及乘除发有相同的优先级而将他们添加到指令集中去实现。代码参考自大神博客:www.cnblogs.com/sxdcgaq8080/p/6270341.html

public class InfixToSuffix {

	private static final Map<Character,Integer> basis = new HashMap<>();
	
	static{
		basis.put('-', 1);
		basis.put('+', 1);
		basis.put('*', 2);
		basis.put('/', 2);
		basis.put('(', 0);
	}
	
	/**
	 * 中缀表达式转换成后缀表达式
	 * 
	 * */
	public String toSuffix(String infix){
		
		//存储数字以及最后的后缀表达式
		List<String> queue = new ArrayList<>();
		//存储运算符,最后stack会被弹空
		List<Character> stack = new ArrayList<>();
		
		//字符数组  用于拆分数字或符号
		char[] charArr = infix.trim().toCharArray();
		String standard = "*/+-()";
		char ch = '$';
		
		//用于记录字符长度  例如100*2,则记录的len为3 到时候截取字符串的前三位就是数字】
		int len = 0;
		
		for(int i = 0; i < charArr.length; i++){
			ch = charArr[i];
			
			//数字
			if (Character.isDigit(ch)) {
				len++;
			}else if (ch == '.') {
				len++;
				
			//若为空格 代表 一段结束
			}else if (Character.isSpace(ch)) {
				if (len > 0) {
					//往队列存入截取的 字符串 
					queue.add(String.valueOf(Arrays.copyOfRange(charArr, i-len, i)));
					//长度置空
					len = 0;
				}
				continue;
			//"*/+-()"中的一个
			}else if (standard.indexOf(ch) != -1) {
				//符号之前的可以截取下来做数字
				if (len > 0) {
					queue.add(String.valueOf(Arrays.copyOfRange(charArr, i-len, i)));
					len = 0;
				}
				//将左括号 放入栈中
				if (ch == '(') {
					stack.add(ch);
					continue;
				}
				if (!stack.isEmpty()) {
					int size = stack.size() - 1;
					boolean flag = false;
					
					//若当前ch为右括号,则栈里元素从栈顶一直弹出,直到弹出到左括号
					while(size >= 0 && ch == ')' && stack.get(size) != '('){
						queue.add(String.valueOf(stack.remove(size)));
						size--;
						flag = true;
					}
					
					//若取得不是()内的元素,并且当前栈顶元素的优先级>=对比元素 那就出栈插入队列
					while(size >= 0 && !flag && basis.get(stack.get(size)) >= basis.get(ch)){
						queue.add(String.valueOf(stack.remove(size)));
						size--;
					}
				}
				
				if (ch != ')') {
					stack.add(ch);
				}else {
					stack.remove(stack.size() - 1);
				}
			} 
			//如果已经走到了中缀表达式的最后一位
			if (i == charArr.length - 1) {
				if (len > 0) {
					queue.add(String.valueOf(Arrays.copyOfRange(charArr, i - len + 1, i + 1)));
				}
				
				int size = stack.size() - 1;
				//一直将栈内 符号全部出栈并且加入队列中
				while(size >= 0) {
					queue.add(String.valueOf(stack.remove(size)));
					size--;
				}
			}
		}
		return queue.toString().substring(1, queue.toString().length()-1);
	}
	
	/**
	  * 将 后缀表达式 进行  运算 计算出结果
	  */
	public String dealEquation(String equation){
		final String ADD = "*";
	    String [] arr = equation.split(",");
	    List<String> list = new ArrayList<String>(); 
	    
	    for (int i = 0; i < arr.length; i++) {
	        int size = list.size();
	        switch (arr[i].trim()) {
	        case "+": 
	        	double a = Double.parseDouble(list.remove(size-2))+ Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(a));
	        	break;
	        case "-": 
	        	double b = Double.parseDouble(list.remove(size-2))- Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(b));
	        	break;
	        case "*": 
	        	double c = Double.parseDouble(list.remove(size-2))* Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(c));
	        	break;
	        case "/": 
	        	double d = Double.parseDouble(list.remove(size-2))/ Double.parseDouble(list.remove(size-2)); list.add(String.valueOf(d));
	        	break;
	        default: list.add(arr[i].trim());     
	        	break;
	        }
	    }
	    
	    return list.size() == 1 ? list.get(0) : "运算失败" ;
	}
}

你可能感兴趣的:(数据结构与算法)