java 实现加减乘除混合运算

初衷:解决小学一年级到四年级 基本加减乘除混合运算

基本思路:

    表达式:100+3+2-200+(10000/5+(100/2))

    此类表达式我们称之为中缀表达式(运算符在数字的中间),如果我们稍加转换,转化为

100, 3, +, 2, +, 200, -, 10000, 5, /, 100, 2, /, +, +  转化后的表达式我们称之为后缀表达式(运算符在数字的后面),先不考虑该表达式是怎么来的,后面我们将详细介绍由中缀表达式转化为后缀表达式的实现过程;我们借助栈的数据结构(后进先出)来辅助我们解决这个问题,拿到转化后的结果 我们先创建一个空栈,从左往右开始运算,具体的运算逻辑为:

          1.遇到数字则入栈
          2.遇到运算符号 则将栈顶两元素出栈
          3.根据运算符号进行运算并将运算结果入栈
          4.表达式结束 则将栈顶元素 取出

我们先靠手来计算一下结果为1955;现在我们用这个规律来进行分析,

第一步:数字100先入栈;

213152_DWxR_1024399.png

第二步:数字3入栈;

213323_Dy7X_1024399.png

第三步: + 则将栈顶的数字3取出,此时栈顶为100 再将数字100取出,将相加后的结果103入栈;

213434_rt3C_1024399.png

第四步:数字2入栈;

213647_VKPJ_1024399.png

第五步:+ 将栈顶数字2取出,继续取出栈顶数字103,将相加后的结果105入栈;

213951_RApi_1024399.png

第六步:200入栈;

214112_ubvm_1024399.png

第七步:- 将栈顶数字200 取出,继续取出栈顶数字105 将相减后结果 -95 入栈;

第八步:数字10000入栈;

第九步:数字5入栈;

第十步:/ 将栈顶数字5 取出 继续取出栈顶数字10000,计算结果为2000,将2000入栈;

第十一步:数字100入栈;

第十二步:数字2入栈;

第十三步:/ 栈顶数字 2 和栈顶数字100 结果为50 入栈;

第十四步:+ 栈顶数字50 和栈顶数字 2000 计算结果为2050 入栈;

第十五步:+ 栈顶数字2050 和栈顶数字-95 计算结果为 1955 入栈;

第十六步:遍历结束,取出栈顶数字 1955

194340_oCpp_1024399.png194912_AVZp_1024399.png

至此结果已经出来了,最终的计算结果为1955

现在来解释刚刚的疑问,后缀表达式该怎么来生成呢??

好了现在我们来一点一点解开未解之谜

1.中缀表达式从左往右遍历,遇到数字则输出

2. 遇到左括号,入栈;遇到右括号 则从栈顶取 一直到取到左括号为止;遇到运算符,优先级不低于当前符号出栈并输出,直到取到比当前优先级低为止(+,-优先级相等,* / 优先级相等,+- 优先级低于 * /)
3.表达式遍历结束 栈内符号依次出栈

还是刚刚的表达式:100+3+2-200+(10000/5+(100/2))

我们来按照这个步骤来分析一下

先创建一个空栈

第一步:数字100 输出;

第二步:+ 入栈;

第三步:数字3 输出;

第四步:+ 栈中没有优先级比+低 故栈中+出栈输出,此处+入栈;

215153_rKpK_1024399.png

第五步:数字2输出;

第六步:- 栈中没有优先级比-低 故栈中+出栈输出,此处-入栈;

215217_dbva_1024399.png

第七步:数字200 输出;

第八步:+ 栈中没有优先级比+低 故栈中 出栈输出,此处+ 入栈;

215245_9hzu_1024399.png

第九步:符号(入栈;

215358_RX3I_1024399.png

第十步:数字10000输出;

第十一步:/ 栈中+ (优先级都没有/ 高 故 / 入栈;

215610_EKLZ_1024399.png

第十二步:数字5 输出;

第十三步:+ 栈顶为/ 优先级高于+ 故+ 入栈 / 出栈输出;

215828_0SsE_1024399.png

第十四步:(入栈;

220055_gO1B_1024399.png

第十五步:数字 100 输出;

第十六步:/ 栈顶为( 此处/入栈;

220248_ACuc_1024399.png

第十七步:数字2 输出;

第十八步:),找到栈顶最近的(之间的符号 / 出栈输出,(出栈;

220502_KaKX_1024399.png

第十九步:),到最近的(之间的符号+ 出栈输出,(出栈;

220650_goUq_1024399.png

第二十步:遍历结束,栈中依次出栈 +

 

从上往下 背景标红部分为后缀表达式的输出顺序

下面为java代码实现 仅供参考

package com.fx.hfirst.strategy;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;
import java.util.regex.Pattern;

public class Compute {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String data = "100+3+2-200+(10000/5+(100/2))";
		String[] dataArray = getDataArray(data);
		String[] postfixArray = getPostFix(dataArray);
		computeWithPostFix(postfixArray);
	}

	private static String[] getDataArray(String data) {
		if (data == null || "".equals(data.trim()) || data.trim().length() < 1) {
			return null;
		}
		int dataLength = data.length();
		String[] dataArray = new String[dataLength];// 根据字符串的长度创建数组
		int top = 0;
		String numStr = "";
		for (int i = 0; i < dataLength; i++) {
			char datai = data.charAt(i);
			String num = String.valueOf(datai);
			if (isNum(num)) {// 数字
				numStr += num;
				if (i + 1 == dataLength) {
					dataArray[top] = numStr;
					top++;
				}
			} else {
				if (!"".equals(numStr)) {// numStr 存在
					dataArray[top] = numStr;// 数字存放到结果数组中
					numStr = "";// 还原
					top++;// 指针下移
				}
				// 符号
				dataArray[top] = num;
				top++;// 指针下移
			}
		}
		return removeNull(dataArray, top);
	}

	/**
	 * 获取后缀表达式
	 * 
	 * @param data
	 * @return
	 */

	private static String[] getPostFix(String[] dataArray) {
		if (dataArray == null || dataArray.length < 1) {
			return null;
		}
		// 1.遍历数组 数字输出
		// 2.若是符号 则判断和栈顶符号的优先级 是右括号 或者优先级低于栈顶符号(乘除高于加减)则栈顶元素依次出栈 输出 并将当前符号入栈
		// 3.数组结束 栈内符号依次出栈
		int dataLength = dataArray.length;
		Stack<String> dataStack = new Stack<String>();
		String[] dataBuffer = new String[dataLength];
		int top = 0;
		for (int i = 0; i < dataLength; i++) {
			String datai = dataArray[i];
			if (isNum(datai)) {// 数字
				dataBuffer[top] = datai;
				top++;// 指针下移
			} else if (isLeftBracket(datai)) {// 左括号
				dataStack.push(datai);// 压栈
			} else if (ComputeEnum.isCompute(datai)) {// 运算符
				List<String> lessThenMeList = getNotLessThenMeta(dataStack,
						datai);
				if (lessThenMeList != null && !lessThenMeList.isEmpty()) {
					for (String lessThen : lessThenMeList) {// 小于当前运算符的符号输出
						dataBuffer[top] = lessThen;
						top++;// 指针下移
					}
				}
				dataStack.push(datai);// 当前元素入栈
			} else if (isRightBracket(datai)) {// 右括号 查找到最近左括号之间的所有符号 出栈
				List<String> betweenLeftBracketList = getBetweenLeftBracketMeta(dataStack);
				if (betweenLeftBracketList != null
						&& !betweenLeftBracketList.isEmpty()) {
					for (String between : betweenLeftBracketList) {// 小于当前运算符的符号输出
						dataBuffer[top] = between;
						top++;// 指针下移
					}
				}
			} else {
				System.err.println("请注意中英文符号,检查出包含不支持的运算符!");
				return null;
			}
		}
		while (!dataStack.isEmpty()) {
			dataBuffer[top] = dataStack.pop();
			top++;// 指针下移
		}
		return removeNull(dataBuffer, top);
	}

	// 根据后缀表达式计算出结果 并打印
	private static void computeWithPostFix(String[] postfixArray) {
		if (postfixArray == null || postfixArray.length < 1) {
			System.err.println("postfixArray is null !");
			return;
		}
		// 1.遇到数字则入栈
		// 2.遇到运算符号 则将栈顶两元素出栈
		// 3.将运算结果入栈
		// 4.数组遍历结束 将栈顶元素 取出
		Stack<String> stack = new Stack<String>();
		for (String meta : postfixArray) {
			if (isNum(meta)) {// 数字
				stack.push(meta);
			} else if (ComputeEnum.isCompute(meta)) {// 运算符号
				double pop = Double.parseDouble(stack.pop());
				double popNext = Double.parseDouble(stack.pop());
				double result = compute(pop, popNext, meta);
				stack.push(String.valueOf(result));
			}
		}
		System.out.println("运算结果为:" + stack.pop());
	}

	private static double compute(double pop, double popNext, String meta) {
		double result = 0;
		ComputeEnum compute = ComputeEnum.get(meta);
		switch (compute) {
		case plus:// 加
			result = popNext + pop;
			break;
		case minus:// 减
			result = popNext - pop;
			break;
		case multiply:// 乘
			result = popNext * pop;
			break;
		case divide:// 除
			if ((pop < 0.000000001) && (pop > -0.000000001)) {
				System.err.println("被除数不能为0!");
				break;
			}
			result = popNext / pop;
			break;
		}
		return result;
	}

	private static List<String> getBetweenLeftBracketMeta(
			Stack<String> dataStack) {
		if (dataStack == null || dataStack.size() < 1) {
			return null;
		}
		List<String> list = new ArrayList<String>(dataStack.size());
		while (!dataStack.isEmpty()) {
			String pop = dataStack.pop();// 栈顶元素出栈
			if (isLeftBracket(pop)) {
				break;
			}
			list.add(pop);
		}
		return list;
	}

	/**
	 * 取出所有不比自己优先级低的元素
	 * 
	 * @param dataStack
	 * @param datai
	 * @return
	 */
	private static List<String> getNotLessThenMeta(Stack<String> dataStack,
			String datai) {
		if (dataStack == null || dataStack.size() < 1) {
			return null;
		}
		ComputeEnum computei = ComputeEnum.get(datai);
		List<String> list = new ArrayList<String>(dataStack.size());
		while (!dataStack.isEmpty()) {
			String pop = dataStack.peek();// 栈顶元素
			ComputeEnum compute = ComputeEnum.get(pop);
			if (compute == null) {
				break;
			}
			if (compute.level < computei.level) {
				break;
			} else {// 优先级高于当前符号 出栈
				dataStack.pop();
				list.add(pop);
			}
		}
		return list;
	}

	private static String[] removeNull(String[] dataArray, int size) {
		String[] dataResult = new String[size];
		System.arraycopy(dataArray, 0, dataResult, 0, dataResult.length);
		return dataResult;
	}

	private static boolean isNum(String num) {
		String reg = "^\\d+$";
		return Pattern.compile(reg).matcher(num).find();
	}

	/**
	 * 左括号
	 * 
	 * @param num
	 * @return
	 */
	private static boolean isLeftBracket(String num) {
		return "(".equals(num);
	}

	/**
	 * 右括号
	 * 
	 * @param num
	 * @return
	 */
	private static boolean isRightBracket(String num) {
		return ")".equals(num);
	}
}

enum ComputeEnum {
	plus("+", 0), // 加法
	minus("-", 0), // 减法
	multiply("*", 1), // 乘法
	divide("/", 1), // 除法
	;

	private static Map<String, ComputeEnum> dataMap = new HashMap<String, ComputeEnum>();
	static {
		dataMap.put(plus.code, plus);
		dataMap.put(minus.code, minus);
		dataMap.put(multiply.code, multiply);
		dataMap.put(divide.code, divide);
	}
	public String code;

	public int level;

	private ComputeEnum(String code, int level) {
		this.code = code;
		this.level = level;
	}

	public static ComputeEnum get(String code) {
		return dataMap.get(code);
	}

	public static boolean isCompute(String code) {
		return dataMap.containsKey(code);
	}
}

 

博客中若有错误,欢迎指正,我们一起来共同完善!

转载于:https://my.oschina.net/fuxingCoder/blog/759250

  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值