逆波兰表达式(后缀表达式)实现简单计算器

利用后缀表达式(波兰表达式)计算出结果,只做了整数
大概步骤是:
1.将中缀表达式 (如:1+((2+3)*4)-5 中的数、运算符、括号放入List集合(方便遍历)
2.将集合中的中缀表达式转为后缀表达式
3.通过后缀表达式计算

中缀表达式转为后缀表达式的具体步骤:
1.从左往右扫描中缀表达式
2.扫描到的是数字,直接放入s2中
3.扫描到的是运算符
* a.如果s1栈是空的或栈顶是左括号,直接放入s1中
* b.否则,如果运算符的优先级大于栈顶运算符的优先级,直接放入s1中
* c.否则,将栈顶的运算符放入s2中,再将当前运算符与栈顶的运算符比较
4.扫描到的是括号
* a.如果是左括号,直接放入s1中
* b.如果是右括号,则依次将s1中栈顶的运算符放入到s2中,直到遇到左括号,此时将左括号和右括号舍弃
5.重复2-4步,直到扫描到中缀表达式最右边
6.如果s1中还有运算符,依次放入s2中,s1变为空
7.依次从s2出栈,出栈后的逆序就是后缀表达式
在这里插入图片描述

通过后缀表达式计算的具体步骤:
1.从左往右扫描后缀表达式
2.如果扫描到数字,直接放入栈s中
3.如果扫描到运算符,从s中pop出两个数,与该运算符进行计算,得到的结果放入栈s中(如:扫描到的运算符是 /,pop出的数依次为6、12,那么注意后从栈中pop出来的放前面,即12/6,结果为2,将结果放入栈中)
4.重复2-3步,直到扫描到后缀表达式的最右边
5.栈s中最后剩下的数就是计算的结果,pop出来

实例代码:

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

/**
 * 逆波兰表达式(后缀表达式)的简单计算机求值
 * @author codewen
 *
 */

public class Calculator {

	//将中缀表达式 (30+4)*5-6 放入List集合的方法
	public static List<String> putInfixExpressionToList(String infixExpression) {
		List<String> infixExpressionList = new ArrayList<String>();//存放中缀表达式的集合
		int index = 0;
		char c;
		while(index < infixExpression.length()) {
			if((c=infixExpression.charAt(index)) > 57 || (c=infixExpression.charAt(index)) < 48) {//如果ASCII码不在48-57之间,就是非数字
				infixExpressionList.add(""+c);
			}else {//如果是数字(要考虑数字是多位的情况)
				String num = "";
				num += c;
				//考虑数字是多位的情况
				while(index+1 < infixExpression.length() && (c=infixExpression.charAt(index+1)) <= 57 && (c=infixExpression.charAt(index+1)) >= 48) {
					index++;
					num += c;
				}
				infixExpressionList.add(num);
			}
			index++;
		}
		return infixExpressionList;
	}
	
	//将集合中的中缀表达式转为后缀表达式的方法
	/**
	 * 1.从左往右扫描中缀表达式
	 * 2.扫描到的是数字,直接放入s2中
	 * 3.扫描到的是运算符
	 * 		a.如果s1栈是空的或栈顶是左括号,直接放入s1中
	 * 		b.否则,如果运算符的优先级大于栈顶运算符的优先级,直接放入s1中
	 * 		c.否则,将栈顶的运算符放入s2中,再将当前运算符与栈顶的运算符比较
	 * 4.扫描到的是括号
	 * 		a.如果是左括号,直接放入s1中
	 * 		b.如果是右括号,则依次将s1中栈顶的运算符放入到s2中,直到遇到左括号,此时将左括号和右括号舍弃
	 * 5.重复2-4步,直到扫描到中缀表达式最右边
	 * 6.如果s1中还有运算符,依次放入s2中,s1变为空
	 * 7.依次从s2出栈,出栈后的逆序就是后缀表达式
	 * @param infixExpressionList
	 * @return
	 */
	public static List<String> infixToPostfixExpression(List<String> infixExpressionList) {
		Stack<String> s1 = new Stack<String>();//存放运算符的栈
		Stack<String> s2 = new Stack<String>();//存放数字的栈
		List<String> postfixExpressionList = new ArrayList<String>();//存放后缀表达式的集合
		//1.从左往右扫描中缀表达式
		for (String s : infixExpressionList) {
			if(s.matches("\\d+")) {//2.扫描到的是数字(通过正则表达式来区分)
				s2.push(s);
			}else {//扫描到的是运算符和括号
				//3.扫描到的是运算符
				if(s.equals("+") || s.equals("-") || s.equals("*") || s.equals("/")) {
					//a.如果s1栈是空的或栈顶是左括号,直接放入s1中	 (peek()查看栈顶,不取出)
					if(s1.size() == 0 || (s1.peek()).equals("(")) {
						s1.push(s);
					}else if(getPriority(s) > getPriority(s1.peek())) {
						//b.否则,如果运算符的优先级大于栈顶运算符的优先级,直接放入s1中
						s1.push(s);
					}else {
						//c.否则,将栈顶的运算符放入s2中,再将当前运算符与栈顶的运算符比较(如果优先级还是小于栈顶优先级,继续)
						while(true) {
							s2.push(s1.pop());
							if(s1.size() == 0 || (s1.peek()).equals("(")) {
								s1.push(s);
								break;
							}else if(getPriority(s) > getPriority(s1.peek())) {
								s1.push(s);
								break;
							}
						}
					}
				}else if(s.equals("(") || s.equals(")")) {//4.扫描到的是括号
					//a.如果是左括号,直接放入s1中
					if(s.equals("(")) {
						s1.push(s);
					}
					//b.如果是右括号,则依次将s1中栈顶的运算符放入到s2中,直到遇到左括号,此时将左括号和右括号舍弃
					if(s.equals(")")) {
						while(true) {
							if((s1.peek()).equals("(")) {
								s1.pop();
								break;
							}
							s2.push(s1.pop());
						}
					}
				} else {
					throw new RuntimeException("符号有误");
				}
			}
		}
		//6.如果s1中还有运算符,依次放入s2中,s1变为空
		while(s1.size() > 0) {
			s2.push(s1.pop());
		}
		//7.依次从s2出栈,出栈后的逆序就是后缀表达式
		List<String> list = new ArrayList<String>();//用于存放s2栈里的符号和数的集合
		while(s2.size() != 0) {
			list.add(s2.pop());
		}
		for(int i=list.size()-1; i>=0; i--) {
			postfixExpressionList.add(list.get(i));
		}
		return postfixExpressionList;
	}
	
	//判断运算符优先级号的方法(优先级号越高,优先级越高)
	public static int getPriority(String s) {
		if(s.equals("+") || s.equals("-")) {
			return 1;
		}else if(s.equals("*") || s.equals("/")) {
			return 2;
		}else {
			return -1;
		}
	}
	
	//两个整数计算的方法
	public static int getResult(int num2, String s, int num1) {
		int result = 0;
		switch (s) {
			case "+" :
				result = num2 + num1;
				break;
			case "-" :
				result = num2 - num1;
				break;
			case "*" :
				result = num2 * num1;
				break;
			case "/" :
				result = num2 / num1;
				break;
			default :
				break;
		}
		return result;
	}
	
	//通过后缀表达式计算的方法
	/**
	 * 1.从左往右扫描后缀表达式
	 * 2.如果扫描到数字,直接放入栈s中
	 * 3.如果扫描到运算符,从s中pop出两个数,与该运算符进行计算,得到的结果放入栈s中
	 * 		(如:扫描到的运算符是 /,pop出的数依次为6、12,那么注意后从栈中pop出来的放前面,即12/6,结果为2,将结果放入栈中)
	 * 4.重复2-3步,直到扫描到后缀表达式的最右边
	 * 5.栈s中最后剩下的数就是计算的结果,pop出来
	 * @param postfixExpressionList
	 * @return
	 */
	public static int calculator(List<String> postfixExpressionList) {
		Stack<Integer> s = new Stack<Integer>();//存放数的栈(也是存放运算结果的栈)
		//1.从左往右扫描后缀表达式
		for (String string : postfixExpressionList) {
			//2.如果扫描到数字,直接放入栈s中
			if(string.matches("\\d+")) {
				s.push(Integer.parseInt(string));
			}else {
				//3.如果扫描到运算符,从s中pop出两个数,与该运算符进行计算,得到的结果放入栈s中(要注意先后顺序,后pop出来的,计算时放运算符前面)
				Integer num1 = s.pop();
				Integer num2 = s.pop();
				Integer result = getResult(num2,string,num1);
				s.push(result);
			}
		}
		//5.栈s中最后剩下的数就是计算的结果,pop出来
		return s.pop();
	}
	
	public static void main(String[] args) {
		String infixExpression = "(30+4) *5-6";
		System.out.println("计算"+infixExpression+":");
		List<String> infixExpressionList = putInfixExpressionToList(infixExpression.replace(" ", ""));
		System.out.println("中缀表达式:"+infixExpressionList);
		List<String> postfixExpressionList = infixToPostfixExpression(infixExpressionList);
		System.out.println("后缀表达式:"+postfixExpressionList);
		int result = calculator(postfixExpressionList);
		System.out.println("结果为:"+result);
	}
}

结果:
在这里插入图片描述

发布了30 篇原创文章 · 获赞 8 · 访问量 1383

猜你喜欢

转载自blog.csdn.net/qq_43598193/article/details/104056577