JAVA 实现简单四则运算

本文介绍了使用JAVA实现简单四则运算的方法,通过栈来处理中缀表达式,重点在于处理符号优先级和括号的问题。详细解释了将中缀表达式转化为逆波兰表达式的过程,并通过一个具体的例子说明了运算的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

刚开始我利用栈的先进后出的特点,遍历运算表达式依次得到expression的每一个字符分别按规则加入符号栈和数字栈,下面代码中继承的ArrStack类是我自己用list实现的栈,java本身有stack的类,里面有我调用的所有方法,变通一下更简单:
1.1 如果符号栈为空直接push
1.2 如果栈不为空 判断优先级 如果当前符号优先级高,直接push ,否则将数字栈的栈顶两个元素 pop,并将符号栈栈顶的符号进行运算得到的结果在push进数字栈。
2.1 如果是数字,要看后面的是数字还是表达式 即多位数的情况要予以考虑。
注意:
1、两个数进行减法运算的时候,要让栈顶元素做被减数。
2、数字的判断退出循环要记得Index–,否则会越界


public class Calculator extends ArrStack{
	public Calculator() {
		super(100);
	}
	public static void main(String[] args) {
		String expression = "200*2+2*10-1";
		Calculator calculator1= new Calculator();
		Calculator calculator2= new Calculator();
		int index = 0;
		int res  = 0;
		char ch = ' ';
		int c = 0;
		String str = "";
		while(true) {
			//依次得到expression的每一个字符
			ch = expression.substring(index, index + 1).charAt(0);
			//判断 ch 是什么,并作出相应的处理
			if(calculator1.Isoper(ch)) {  //运算符
				if(calculator1.IsEmpty()) {  //符号栈为空
					calculator1.push(ch);  //直接push 
				}else {      // 判断优先级
					if(priorty(calculator1.pick()) <priorty(ch) ){  //当前优先级高
						calculator1.push(ch);  //直接push 
					}else {
						res = calculator1.cal( calculator2.pop(),  calculator2.pop(),  calculator1.pop()); 
						calculator2.push(res);
						calculator1.push(ch);
					}
				}
			}else {  //如果是数字,要看后面的是数字还是表达式
				if(index == expression.length() - 1) {
					calculator2.push(Integer.parseInt(expression.substring(index, index + 1)));
					break;
				}else { 
					while(true) {
						if(calculator1.Isoper(expression.substring(index, index + 1).charAt(0))) {
							index --;
							break;
						}else{
							str = str +  expression.substring(index, index + 1);
						}
						index ++;
					}
					c = Integer.parseInt(str);
					calculator2.push(c);  //char --> int
					str = "";
				}
			}
			index ++;
			if(index >= expression.length()) {
				break;
			}
		}
		while(!calculator1.IsEmpty()) {
			res = calculator1.cal( calculator2.pop(),  calculator2.pop(),  calculator1.pop()); 
			calculator2.push(res);
		}
		System.out.println(res);
	}
	
	//返回运算及的优先顺序,数字越大,优先级最高
	public static int priorty(int i) {
		if(i == '*' || i == '/') {
			return 1;
		}else if(i == '+' || i == '-') {
			return 0;
		}else {
			return -1;
		}
	}
	
	//判断是不是运算符
	public boolean Isoper(char val) {
		return val =='+' ||val =='-' || val == '*' || val =='/';
	}
	//计算方法
	public int cal  (int num1, int num2,int i) {
		int res = 0; 
		if(i== '+') {
			res =num1 + num2;
		}else if(i== '-') {
			res =num2 - num1;
		}else if(i== '*') {
			res =num1 * num2;
		}else if(i== '/') {
			res =num1 / num2;
		}
		return res;
	}
}

这是我将中缀表达式转成逆波兰表达式后模拟的计算器,代码更为简单,因为计算机使用逆波兰表达式进行计算不需要太多的步骤,但大家需要理解中缀表达式和逆波兰表达式的转换过程。
举个例子吧:比如将:2*(9+6/3-5)+4转化为后缀表达式2 9 6 3 / +5 - * 4 + ]

1、任何中缀表达式都由运算数,运算符,括号(大,中,小),这三部分组成。

2、从中缀表达式的左边开始扫描(脑中自己想像的),若遇到运算数时,则直接将其输出(不压入堆栈)。

3、若遇到左括号,则将其压栈。

4、若遇到右括号,表达括号内的中缀表达式已经扫描完毕。这时需将栈顶的运算符依次弹出并输出,直至遇到左括号[左括号弹出但不输出]。

5、若遇到的是运算符:
a、如果该运算符的优先级大于栈顶运算符的优先级时,将其压栈
b、如果该运算符的优先级小于栈顶运算符的优先级时,将栈顶运算符弹出并输出,接着和新的栈顶运算 符比较,若大于,则将其压栈,若小于,继续将栈顶运算符弹出并输出…(一直递归下去,直至运算符大于栈顶云算符为止)。

6、最后一步,若扫描到中缀表达式的末尾[即扫描结束],若堆栈中还有存留的运算符依次弹出并输出即可。

肯定有一些读者还是没完全弄懂(毕竟全都是文字)。接下来,举一个例子:帮助大家消化

(1)out:2 stack:

(2)out:2 stack:*

(3)out:2 stack: * (

(4)out:2 9 stack :* (

(5)out:2 9 stack :* ( + 注:在堆栈中括号的优先级最低

(6)out:2 9 6 stack :* ( +

(7)out :2 9 6 stack :* ( + /

(8)out :2 9 6 3 stack :* ( + /

(9)out :2 9 6 3 / stack :* ( +

(10)out: 2 9 6 3 / + stack : * (

(11)out:2 9 6 3 / + stack : * ( -

(12)out : 2 9 6 3 / + 5 stack : * ( - 遇到了右括号

(13)out:2 9 6 3 / + 5 - stack:* (

(14)out:2 9 6 3 / + 5 - stack:*

(15)out:2 9 6 3 / + 5 - stack :* 括号弹出但不输出

(16)out :2 9 6 3 / + 5 - * stack : 遇到了+

(17)out:2 9 6 3 / + 5 - * stack :+

(18)out:2 9 6 3 / + 5 - * 4 stack : +

(19)out:2 9 6 3 / + 5 - * 4 + stack :

package Stack;

import java.util.ArrayList;
import java.util.List;
import java.util.Stack;

public class PolandNotation {
	public static void main(String[] args) {
		String expression = "10+((2+3)*4)-5";
		//将"1+((2+3)*4)-5"转成[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]
		//将[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]转成成后缀表达式[10, 2, 3, +, 4, *, +, 5, -] 
		List<String> list1  = expressionTolist(expression);
		List<String> list2  = parsesuffixExpressionlist(list1);
		System.out.println(list1 + "================");
		System.out.println(list2 + "=list2");
		System.out.println(caculate(list2));
	}
	//中缀表达式list转成后缀表达式的arrayList
	public static List<String> parsesuffixExpressionlist(List<String> ls){
		//定义两个栈 
		Stack<String> s1 = new Stack<String>();  //符号栈
		//stack2这个栈没有pop操作并且最后需要逆序才能得到逆波兰表达式,所以采用arraylis代替
		List<String> s2 = new ArrayList<String>();
		//遍历ls  获取到每一个字符
		for (String item : ls) {
			if(item.matches("\\d+")) { //如果是一个数 直接加入s2
				s2.add(item);
			}else if(item.equals("(")) { //如果是"(", 直接压入s1
				s1.push(item);
			}else if(item.equals(")")) { //如果是")",则依次弹出s1栈的运算符,直到遇到左括号为止,此时将这一对括号丢弃
				while(!s1.peek().equals("(")) {
					s2.add(s1.pop());
				}
				s1.pop();  //将"("弹出
			}else {  //运算符  将item的优先级和s1栈顶比较
				while(s1.size() != 0 && Operation.priorty(s1.peek()) >= Operation.priorty(item) ) {
					s2.add(s1.pop());
				}
				//将 item压入栈中
				s1.push(item);
			}
		}
		//将 s1中剩余的运算符压入s2 中
		while(s1.size()!= 0) {
			s2.add(s1.pop());
		}
		return s2;//因为 s2本身是一个链表,故此按序输出就是逆波兰表达式
	}
	//将中缀表达式转换成list 
	public static List<String> expressionTolist(String str){
		List<String> list = new ArrayList<String>();
		int i = 0;  // 遍历
		String s;  //多位数的拼接
		do {
			s = "";  // 此处一定要使 s 为空串。。。。。。。。。。。。。。。。。
			//如果是一个非数字,直接加入到list
			if(str.charAt(i) < 48 || str.charAt(i) > 57) {
				list.add(str.charAt(i) + "");
				i ++;
			}else {  //如果是数字考虑多位数的问题
				while(i < str.length() && str.charAt(i) >= 48 && str.charAt(i) <= 57) {
					s = s + str.charAt(i);  //拼接
					i++;
				}
				list.add(s);
			}
		}while( i < str.length());
		return list;
	}
	public static int caculate(List<String> list) {
		Stack<String> stack = new Stack<String>();
		//遍历list
		for (String string : list) {
			if(string.matches("\\d+")) {
				//入栈
				stack.push(string);
			}else {
				//pop出两个数,进行运算,并将结果push进栈
				int num1 = Integer.parseInt(stack.pop());
				int num2 = Integer.parseInt(stack.pop());
				int res  = 0;
				if(string.equals("+")){
					res =num1 + num2;
				}else if(string.equals("-")) {
					res =num2 - num1;
				}else if(string.equals("*")) {
					res =num1 * num2;
				}else if(string.equals("/")){
					res =num1 / num2;
				}else {
					throw new RuntimeException("运算符异常");
				}
				stack.push(res + "");
			}
		}
		return Integer.parseInt(stack.pop());
	}

}
class Operation{
	 private static int ADD = 1;
	 private static int SUB = 1;
	 private static int MUL = 2;
	 private static int DIV = 2;
	//返回运算及的优先顺序
		public static int priorty(String operation) {
			int res = 0;
			if(operation.equals("+") ) {
				res = ADD;
			}else if(operation.equals("-") ) {
				res = SUB;
			}else if(operation.equals("*") ) {
				res = MUL;
			}else if(operation.equals("/") ) {
				res = DIV;
			}else {
				System.out.println("不存在该运算符");
			}
			return res;
		}
		
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值