Java数据结构与算法 前缀-中缀-后缀表达式

各种表达式

前缀(波兰),中缀,后缀表达式(逆波兰)
中缀:(3+4)*5-6
前缀: - * + 3 4 5 6(从右至左进行运算)
后缀:3 4 + 5 * 6 - (从左向右进行运算)

前面,我们利用栈实现了一个简单的中缀表达式计算器。实际在计算机中,更多利用的是由后缀表达式来计算。下面。我们讨论如何使用后缀表达式计算结果 和 如何将 中缀表达式 转化为后缀表达式。

逆波兰表达式计算

对这样一个逆波兰表达式3 4 + 5 * 6 - ,中缀【(3+4)*5-6)】我们采用以下算法步骤来计算最终结果

  1. 建立一个数栈stack1
  2. 建立一个索引来遍历接受的表达式,初始化index=0
  3. 遍历表达式,若遇到数字直接入栈,遇到符号则从stack1中弹栈两个数字,并将运算结果重新压栈到stack1中。
  4. 重复步骤3直到表达式遍历完毕。

因此对于3 4 + 5 * 6 - 我们有以下步骤:

遍历表达式item 操作 stack1中元素(从栈底到栈顶)
0 3入栈 3
4 4入栈 3,4
+ 4,3弹栈并运算结果为7,7入栈 7
5 5入栈 7,5
* 5,7弹栈运算结果的35,35入栈 35
6 6入栈 35,6
- 6,35弹栈运算35-6=29,29入栈 29
运算结束,栈顶元素即为最终运算结果 29

Note that 注意每次弹栈两个进行运算时,后弹出的元素应该放在运算符前面。比如对于除法操作,应该是 后弹出的元素/ 先弹出的元素 作为运算结果。

这里,我们采用java自带的java.util.Stack进行程序编写

package com.like.java.data_structure.stack;

import java.util.Arrays;
import java.util.Stack;

public class PolandNotation {
	public static void main(String[] args) {
		// 一个逆波兰后缀表达式
		String expString = "300 4 + 5 * 6 -";
		
		// 建立数栈
		String[] list = expString.split(" ");
		System.out.println(Arrays.toString(list));
		Stack<Integer> numStack = new Stack<Integer>();
		
		for(String each:list)
		{
			if(each.matches("\\d+"))
			{
				numStack.push(Integer.parseInt(each));
				continue;
			}
			
			int num2 = numStack.pop();
			int num1 = numStack.pop();
			int res = 0;
			
			if(each.contentEquals("+"))
			{
				res = num2 + num1;
			}else if(each.contentEquals("-"))
			{
				res = num1 - num2;
			}else if(each.contentEquals("*"))
			{
				res = num1 * num2;
			}else {
				res = num1/num2;
			}
			numStack.push(res);
		}
		System.out.println("运算结果:"+numStack.pop());
	}
}

中缀表达式->后缀表达式

例如对于这样一个中缀表达式:1 + ( ( 2 + 3 ) * 4 ) - 5,转为后缀表达式思想
1)创建两个栈:运算符栈s1和存储中间结果得栈s2(也可以采用普通的数组结构)
2)从左到右依次扫描中缀表达式
3)遇到操作数时,将其压入s2
4)遇到运算符时,比较与s1栈顶元素运算符得优先级
4.1 若s1为空或者栈顶元素为(,直接压栈
4.2 若当前运算符大于栈顶运算符,直接压栈‘
4.3 否则,s1栈顶弹栈到s2,并拿当前运算符和下一个栈顶元素继续比较,转4.1
5)遇到括号时(括号不算运算符)
5.1 若是左括号,直接压栈
5.2 若是右括号,s1弹栈并压入s2直到遇到一个左括号,舍弃左右括号
6)重复2-5直到表达式最右边
7) 将s1剩余元素依次弹栈并压入s2
8)依次弹出s2元素,逆序即为最终得后缀表达式

 Note that: s2只有压栈操作,后面还需要逆序输出,其实可以用一个list来替代

Java代码

package com.like.java.data_structure.stack;

import java.util.ArrayList;
import java.util.Stack;
import java.util.concurrent.PriorityBlockingQueue;

// 中缀表达式转为后缀表达式
public class parseSuffix {
	public static void main(String[] args) {
		String expression = "1 + ( ( 2 + 3 ) * 4 ) - 5";
		String[] val = expression.split(" ");
		int index = 0;
		
		// 利用一个栈和数组,数组用于存储中间运算结果
		Stack<String> stack = new Stack<String>();
		ArrayList<String> list = new ArrayList<String>();
		
		String c = " ";
		
		while(index < val.length)
		{
			 // 当前元素
			 c = val[index];
			 // 如果是数字直接加到list中
			 if(Character.isDigit(c.charAt(0)))
			 {
				 list.add(c);
			 }
			 // 否则,如果栈为空,或者栈顶元素为(, 或者要处理的元素为(,直接入栈
			 else if(stack.empty() || stack.peek().equals("(") || c.equals("("))
			 {
				 stack.push(c);
			 }
			 // 若是运算符,则比较优先级。若优先级不高于栈顶,则栈顶元素不断出栈到list中。
			 else if( c.contentEquals("*")|| c.contentEquals("/")|| c.contentEquals("+")||c.contentEquals("-"))
			 {
				 System.out.println("符号遇到");
				 while(!stack.empty())
				 {
					 char cur = c.charAt(0);
					 char top = stack.peek().charAt(0);
					 System.out.println("比较符号");
					 System.out.println(cur+":"+top);
					 if(Priority(cur)>Priority(top))
					 {
						 stack.push(c);
						 break;
					 }else {
						list.add(stack.pop());
					}
				 }
			 }
			 // 若遇到右括号,则不断弹栈直到遇到一个左括号
			 if(c.contentEquals(")"))
			 {
				
				 while(!stack.empty() && !stack.peek().contentEquals("("))
				 {
					 list.add(stack.pop());
				 }
				 // 弹出左括号
				 stack.pop();
			
			 }
		    index ++;
		}
		System.out.println(list);
	}
	
	// 设定运算符优先级
	public static int Priority(char oper)
	{
		switch(oper)
		{
		case '+':
		case '-':
			return 1;
		case '*':
			return 2;
		case '/':
			return 2;
		default:
			return 0;
		}
	}
	
	
}

发布了80 篇原创文章 · 获赞 332 · 访问量 70万+

猜你喜欢

转载自blog.csdn.net/qq_40527086/article/details/104342230
今日推荐