数据结构Stack之中缀表达式转后缀表达式运算应用

Posted by Naah on Tuesday, Aug 08,2017 12:59:05

通过学习java中的Stack栈,写一个一个简单的中缀表达式转换为后缀表达式并计算的应用

由于时间问题,没有写字符分割函数。暂时用空格进行分割


import java.util.Iterator;
import java.util.Stack;

public class Suffix2Infix {

	public static void main(String[] args) {
		// 创建对象
		OperaExpression oe = new OperaExpression();

		// 要计算得公式
		// 没有去写辨别多位数的字符串方法,于是目前使用空格进行区分符号与数字
		String ex = "9 + ( 3 - 1 * 3 ) * 3 + 10 / 2";

		// 输出结果
		System.out.println("结果:" + oe.getResult(ex));
	}

}

class OperaExpression {
	// 后缀表达式栈
	public Stack exp = new Stack();

	// 符号栈
	public Stack sym = new Stack();

	/**
	 * 返回结果方法
	 * @param ex 中缀表达式
	 * @return 结果
	 */
	public double getResult(String ex) {
		// 中缀表达式转换为后缀表达式
		System.out.println("中缀表达式:" + ex.replaceAll(" ", ""));
		String ae = getAfterExpress(ex);
		System.out.println("后缀表达式:" + ae);

		// 计算结果
		double result = operaBackExpress();
		return result;
	}

	/**
	 * 计算后缀表达式方法
	 * @return 表达式运算结果
	 */
	private double operaBackExpress() {
		// 创建结果栈
		Stack result = new Stack();

		// 遍历后缀表达式栈
		for (Iterator iterator = exp.iterator(); iterator.hasNext();) {

			// 得到栈内元素
			String string = (String) iterator.next();

			// 数字则存入结果栈
			if (getType(string) == 1) {
				result.push(Double.parseDouble(string));
			}
			// 如果非数字则进行计算
			else {

				// 取出结果栈内要计算的值
				double a2 = result.pop();
				double a1 = result.pop();

				// 对值进行计算
				double res = opera(a1, a2, string);

				// 讲结果存入结果栈
				result.push(res);
			}
		}

		// 取出结果栈内最终得结果
		return result.pop();
	}

	/**
	 * 运算方法
	 * @param a1 第一个值
	 * @param a2 第二个值
	 * @param string 符号
	 * @return 计算结果
	 */
	private double opera(double a1, double a2, String string) {
		switch (string) {
		case "+":
			return a1 + a2;
		case "-":
			return a1 - a2;
		case "*":
			return a1 * a2;
		case "/":
			return a1 / a2;
		default:
			throw new RuntimeException(string + "运算错误");
		}
	}

	/**
	 * 中缀表达式转后缀表达式方法
	 * @param ex 中缀表达式
	 * @return 后缀表达式栈
	 */
	private String getAfterExpress(String ex) {

		// 得到元素数组
		String[] spilt = getArray(ex);

		// 遍历数组
		for (String c : spilt) {

			// 得到元素类型
			int numOrsym = getType(c);
			switch (numOrsym) {

			// 1为数字,存入表达式栈
			case 1:
				exp.push(c + "");
				break;

			// 其他则进行符号判定,之后存入表达式栈
			default:

				// 进行符号判定
				checkSym();

				// 存入表达式栈
				sym.add(c);
				break;
			}

		}
		// 符号优先级插入运算,用于将剩余符号进行运算插入后最表达式栈
		highLevel(sym);

		// 讲后缀表达式栈转换为字符串
		String ae = "";
		for (Iterator iterator = exp.iterator(); iterator.hasNext();) {
			ae = ae + iterator.next();

		}
		// 返回字符串
		return ae;
	}

	/**
	 * 表达式分解数组方法
	 * @param ex 中缀表达式
	 * @return 元素数组
	 */
	private String[] getArray(String ex) {
		String[] split = ex.split(" ");
		return split;
	}

	/**
	 * 符号判定
	 */
	private void checkSym() {
		// 符号栈内元素超过一个时进入
		if (sym.size() > 1) {

			// 符号栈内包含左括号时进入
			if (sym.contains("(")) {

				// 如果符号栈内包含右括号,并且右括号为栈顶元素时进入
				if (sym.contains(")") && sym.indexOf(")") + 1 == sym.size()) {

					// 缓冲变量
					String i;

					// 创建括号内符号缓冲栈
					Stack buffer = new Stack();

					// 取出元素不等于左括号时运行
					while (!(i = sym.pop()).equals("(")) {

						// 取出元素如果为右括号,结束本次循环,进入下次循环
						if (i.equals(")"))
							continue;

						// 将符号存入符号缓存栈
						buffer.push(i);
					}

					// 将符号缓存栈进行优先级运算,并存入后缀表达式栈
					highLevel(buffer);
				}

				// 符号栈内不包含括号,并且符号元素为两个时进行运算
			} else if (sym.size() == 2) {

				// 将符号栈元素运算至后缀表达式栈
				popSym();
			}

		}

	}

	/**
	 * 符号栈内多符号元素的优先级运算方法
	 * 运算后存入后缀表达式栈
	 * @param buffer 符号栈
	 */
	private void highLevel(Stack buffer) {

		// 包含乘除法时
		while (buffer.contains("*") | buffer.contains("/")) {

			// 如果包含乘法
			if (buffer.contains("*")) {

				// 符号栈移除乘号
				buffer.removeElement("*");

				// 后缀表达式栈存入乘号
				exp.push("*" + "");
			}

			// 如果包含除法
			if (buffer.contains("/")) {

				// 符号栈溢出除号
				buffer.removeElement("/");

				// 后缀表达式栈存入除号
				exp.push("/" + "");
			}
		}

		// 剩余符号,无序存入后缀表达式栈
		while (buffer.size() != 0) {
			exp.push(buffer.pop() + "");
		}
	}

	/**
	 * 符号栈内两元素优先级运算方法
	 * 运算后存入后缀表达式
	 */
	private void popSym() {

		// 取出第一个符号
		String a1 = sym.pop();

		// 取出第二个符号
		String a2 = sym.pop();

		// 通过符号类型运行优先级
		if (getType(a1) > getType(a2)) {
			exp.push(a1 + "");
			exp.push(a2 + "");
		} else {
			exp.push(a2 + "");
			exp.push(a1 + "");
		}
	}

	/**
	 * 元素类型及符号优先级运算
	 * @param word 元素
	 * @return
	 */
	private int getType(String word) {

		// 取出首位符号(主要用于辨别数字与符号)
		char[] cs = word.substring(0, 1).toCharArray();

		// 默认辨识符
		char one = '`';
		if (cs.length == 1) {

			// 首位符号作为辨识符
			one = cs[0];
		}

		// 如果首位元素的ascii码在0-9之间则为数字
		if (one >= '0' && one <= '9') {
			return 1;
		}

		// 否则则为符号
		else {
			switch (word) {
			case "(":

				return 41;
			case ")":

				return 42;
			case "*":

				return 31;
			case "/":

				return 32;
			case "+":

				return 21;
			case "-":

				return 22;
			default:
				throw new RuntimeException(word + "字段错误");
			}
		}

	}

}