中缀表达式转逆波兰表达式以及逆波兰表达式求值代码实现

中缀表达式

中缀表达式就是常见的运算表达式,如(3+4)×5-6

中缀表达式的求值是我们人最熟悉的,但是对计算机来说却不好操作,因此,在计算结果时,往往会将中缀表达式转成其它表达式来操作(一般转成后缀表达式.)

后缀表达式

后缀表达式又称逆波兰表达式,与前缀表达式相似,只是运算符位于操作数之后

中举例说明: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 –

后缀表达式的计算机求值

从左至右扫描表达式,遇到数字时,将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 和 栈顶元素),并将结果入栈;重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果

例如: (3+4)×5-6 对应的后缀表达式就是 3 4 + 5 × 6 - , 针对后缀表达式求值步骤如下:

从左至右扫描,将3和4压入堆栈;
遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
将5入栈;
接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
将6入栈;
最后是-运算符,计算出35-6的值,即29,由此得出最终结果

在此篇文章中:
我们首先介绍一下中缀表达式转后缀表达式的思路
大家看到,后缀表达式适合计算式进行运算,但是人却不太容易写出来,尤其是表达式很长的情况下,因此在开发中,我们需要将 中缀表达式转成后缀表达式。

具体步骤如下:
1)初始化两个栈:运算符栈s1和储存中间结果的栈s2;
2)从左至右扫描中缀表达式;
3)遇到操作数时,将其压s2;
4)遇到运算符时,比较其与s1栈顶运算符的优先级:
(1)如果s1为空,或栈顶运算符为左括号“(”,则直接将此运算符入栈;
(2)否则,若优先级比栈顶运算符的高,也将运算符压入s1;
(3)否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;
5)遇到括号时:
(1) 如果是左括号“(”,则直接压入s1
(2) 如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃
6)重复步骤2至5,直到表达式的最右边
7)将s1中剩余的运算符依次弹出并压入s2
8)依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

思路清晰了,我们来看看代码

public class PolandNotation {
	
	private final static int ADD = 1;
	private final static int SUB = 1;
	private final static int MUL = 2;
	private final static int DIV = 2;
	
	public static void main(String[] args) {

		// 把中缀表达式 转换为 后缀表达式
		String expression = "1+((2+3)*4)-5";
		
		List infixExpressionList = toInfixExpressionList(expression);
		System.out.println("中缀表达式对应的List=" + infixExpressionList);

		List suffixExpreesionList = parseSuffixExpreesionList(infixExpressionList);
		System.out.println("后缀表达式对应的List" + suffixExpreesionList); // ArrayList [1,2,3,+,4,*,+,5,–]
		
		System.out.println(calculate(suffixExpreesionList));
	}

	/**
	 *
	 * @param infixExpressionList
	 * @return
	 */
	private static List parseSuffixExpreesionList(List ls) {
		List s2 = new ArrayList<>();
		Stack s1 = new Stack();
		// 遍历ls
		for (String item : ls) {
			if (item.matches("\\d+")) {
				s2.add(item);
			}else if ("(".equals(item)) {
				s1.push(item);
			}else if (")".equals(item)) {
				while (!"(".equals(s1.peek())) {
					s2.add(s1.pop());
				}
				s1.pop();
			} else if (s1.empty()) {
				s1.push(item);
			} else if(getValue(s1.peek()) < getValue(item)) { // 优先级大于
				s1.push(item);
			} else {// 当item的优先级小于等于s1栈顶运算符, 将s1栈顶的运算符弹出并加入到s2中,再次转到(4.1)与s1中新的栈顶运算符相比较
				while (true) {
					if (s1.isEmpty() ||  getValue(s1.peek()) < getValue(item) ) {
						s1.push(item);
						break;
					}
					s2.add(s1.pop());
				}
			}
		}
		// 全部扫描完毕 将 s1 中剩余的运算符依次弹出并压入 s2
		while (!s1.isEmpty()) {
			s2.add(s1.pop());
		}

		return s2;
	}
	/**
	 * 把表达式 放入数组
	 * 
	 * @param expression
	 * @return
	 */
	private static List toInfixExpressionList(String expression) {
		// String expression = "1+((2+3)*4)-5";
		String cr = "";
		List ls = new ArrayList<>();
		int index = 0;
		String keepNum = "";
		while (true) {
			cr = expression.substring(index, index + 1);
			if (isOper(cr)) { // 如果是操作符则直接加入
				ls.add(cr);
			} else {// 数字 还要在看下后面是否还是数字 主要是多位数的问题

				keepNum += cr;
				if (index == expression.length() - 1) { // 如果是最后一位数了 就不要往后判断了
					ls.add(keepNum);
					return ls;
				}
				cr = expression.substring(index + 1, index + 2);

				if (isOper(cr)) {
					ls.add(keepNum);
					keepNum = "";
				}
			}
			index++;
			if (index >= expression.length()) {
				break;
			}
		}
		return ls;
	}

	/**
	 * 从左至右扫描表达式,遇到数字时, 将数字压入堆栈,遇到运算符时,弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素 和 栈顶元素),并将结果入栈;
	 * 重复上述过程直到表达式最右端,最后运算得出的值即为表达式的结果
	 * 
	 * @param list
	 * @return
	 */
	private static int calculate(List list) {

		Stack stack = new Stack();
		for (String item : list) {
			if (item.matches("\\d+")) { // 匹配到的数
				stack.push(Integer.parseInt(item));
			} else {
				Integer num1 = stack.pop();
				Integer num2 = stack.pop();
				int res = 0;
				if ("+".equals(item)) {
					res = num1 + num2;
				} else if ("-".equals(item)) {
					res = num2 - num1;
				} else if ("*".equals(item)) {
					res = num1 * num2;
				} else if ("/".equals(item)) {
					res = num2 / num1;
				} else {
					throw new RuntimeException("运算符有误");
				}
				// 把res 入栈
				stack.push(res);
			}
		}
		return stack.pop();
	}

	public static boolean isOper(String c) {
		return "*".equals(c) || "/".equals(c) || "+".equals(c) || "-".equals(c) || "(".equals(c) || ")".equals(c);
	}

	// 写一个方法,返回对应的优先级数字
	public static int getValue(String operation) {
		int result = 0;
		switch (operation) {
		case "+":
			result = ADD;
			break;
		case "-":
			result = SUB;
			break;
		case "*":
			result = MUL;
			break;
		case "/":
			result = DIV;
			break;
		default:
			System.out.println("不存在该运算符" + operation);
			break;
		}
		return result;
	}
}

关于数据结构和算法的所有源码,可以在作者的github上下载
github:https://github.com/magicxiexiaodong/DataStructure

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