使用栈实现中缀表达式转换成后缀表达式并计算结果(逆波兰计算器)

一、中缀表达式转换成后缀表达式

具体步骤如下:

1、初始化栈stack(暂时存放运算符)以及集合list(存放后缀表达式)

2、从左向右扫描中缀表达式

3、当前元素为数字时,直接添加到list中

4、当前元素为运算符时,需要比较当前运算符与stack中栈顶运算符的优先级

      4.1、若stack为空,或者栈顶运算符为 '(' 时,当前运算符直接入栈

      4.2、stack不为空,当前运算符优先级高于栈顶运算符时,则将当前运算符直接入栈;

                                     当前运算符优先级小于等于栈顶运算符时,则将栈顶运算符出栈添加到list中,                                                                                 并重复4.1-4.2,将当前运算符继续与新的栈顶运算符比较。

5、当前元素为 '(' 时,直接压入stack中

6、当前元素为 ')' 时,循环stack,一次弹出stack栈顶运算符并添加到list中,直到遇到 '(' 为止,此时将栈顶运算符为 '(' 时直接出          栈,继续扫描下一元素

7、重复步骤 2 至 6,直到中缀表达式被扫描完

8、将stack栈中剩余的运算符依次弹出并添加到list中,最后得到后缀表达式

 例1:中缀表达式:60 + 8 / 2

扫描到的元素 stack(栈底->栈顶) list 说明
60 60 数字,直接添加到list
+ + 60 栈空,运算符直接入栈
8 + 60,8 数字,直接添加到list
/ +,/ 60,8 / 优先级比 + 高,直接入栈
2 +,/ 60,8,2 数字,直接添加到list
扫描结束 + 60,8,2,/ 弹出栈顶运算符
扫描结束 60,8,2,/,+ 弹出栈顶运算符

例2:中缀表达式 1+((2+3)*4)-6/2

扫描到的元素 stack(栈底->栈顶) list 说明
1 1 数字,直接添加到list
+ + 1 栈空,运算符直接入栈
( +,( 1 左括号,直接入栈
( +,(,( 1 左括号,直接入栈
2 +,(,( 1,2 数字,直接添加到list
+ +,(,(,+ 1,2 栈顶为 ( 时,运算符直接入栈
3 +,(,(,+ 1,2,3 数字,直接添加到list
) +,(, 1,2,3,+

),(1)栈中运算符依次弹出添加到list,直到遇到左括号为止,(2)将栈中左括号弹出

* +,(,* 1,2,3,+ 栈顶元素为 ( 时,运算符直接入栈
4 +,(,* 1,2,3,+,4 数字,直接添加到list
) + 1,2,3,+,4,* ),(1)栈中运算符依次弹出添加到list,直到遇到左括号为止,(2)将栈中 ( 弹出
- - 1,2,3,+,4,*,+ - 与 + 两运算符优先级相等,(1)弹出栈顶运算符+并添加到list,(2) - 入栈
6 - 1,2,3,+,4,*,+,6 数字,直接添加到list
/ -,/ 1,2,3,+,4,*,+,6 / 优先级高于 -,将 / 入栈
2 -,/ 1,2,3,+,4,*,+,6,2 数字,直接添加到list
扫描结束 1,2,3,+,4,*,+,6,2,/,- 将栈中剩余运算符依次弹出添加到list

代码实现:

//1 先将表达式转换成list	
public static List<String> expressionToList(String expression){
		int i = 0;//下标,用于扫描表达式
		char ch;//用于接收扫描字符
		String numStr;//用于拼接多位数
		ArrayList<String> list = new ArrayList<String>();//存放表达式
		do {
			//需要判断ch是操作符还是数字,此处不理解的可以百度ACSII码
			if((ch = expression.charAt(i)) < 48 || (ch = expression.charAt(i)) > 57) {
				list.add(""+ch);
				i++;
			}else {//如果是数字,则需要判断是否是多位数
				numStr = "";
				while(i < expression.length() && (ch = expression.charAt(i)) >= 48 && (ch = expression.charAt(i)) <= 57) {
					numStr+=ch;
					i++;
				}
				list.add(numStr);
			}
		}while(i < expression.length());
		return list;
	}


//2 将中缀表达式转为后缀表达式	
public static List<String> parseSuffixExpressionList(List<String> list){
		Stack<String> stack = new Stack<String>();
		ArrayList<String> resList = new ArrayList<String>();
		
		//循环中缀表达式
		for(String item : list) {
			//是多位数时直接入栈
			if(item.matches("\\d+")) {
				resList.add(item);
			//运算符时需要判断入栈
			}else if(item.equals("(")) {
				stack.push(item);
			}else if(item.equals(")")) {
				while(true) {
					if(stack.peek().equals("(")) {
						break;
					}
					resList.add(stack.pop());
				}
				//此时需要将)弹出
				stack.pop();
			}else {
				//(当前运算符优先级小于等于栈顶运算符)直接将栈顶元素出栈放入list
				while(stack.size()!=0 && priority(item) <= priority(stack.peek())) {
					resList.add(stack.pop());
				}
				//还需要将item压入栈中
				stack.push(item);
			}
		}
		//将栈中剩余运算符弹出放入到resList
		while(stack.size()!=0) {
			resList.add(stack.pop());
		}
		return resList;
	}

	
    //数字越大,则优先级就越高
	public int priority(String oper) {
		int result = 0;
		if(oper.equals("*") || oper.equals("/")) {
			return 2;
		}else if(oper.equals("+") || oper.equals("-")){
			return 1;
		}else {
//			System.out.println("不存在此运算符");
			return result;
		}
	}

二、后缀表达式计算(不包含小数情况)

具体步骤如下:

1、初始化栈stack,并将后缀表达式从左向右扫描

2、当前元素为数字时,直接入栈

3、当前元素为运算符时,依次弹出栈中两个数字,并进行运算,得到结果后入栈

4、重复1-3

直接上例子:(5+4)*3-7 对应的后缀表达式为 5 4 + 3 * 7 - 

1、从左向右扫描,将 5 和 4 入栈

2、遇到运算符 +,依次弹出栈中 4 和 5(4为栈顶元素,5为次顶元素),计算出 4 + 5 = 9,将 9 入栈

3、将数字 3 入栈。

4、遇到运算符 *,依次弹出栈中 3 和 7,计算出 3 * 9 = 27,将 27 入栈

5、将数字 7 入栈。

6、遇到运算符 -,依次弹出栈中 27 和 7,计算出 27 - 7 = 20,此时已扫描结束,最终结果为 20

//1 首先将表达式转换成list
public List<String> expressionToList(String expression){
		int i = 0;//下标,用于扫描表达式
		char ch;//用于接收扫描字符
		String numStr;//用于拼接多位数
		ArrayList<String> list = new ArrayList<String>();//存放表达式
		do {
			//需要判断ch是操作符还是数字,此处不理解的可以百度ACSII码
			if((ch = expression.charAt(i)) < 48 || (ch = expression.charAt(i)) > 57) {
				list.add(""+ch);
				i++;
			}else {//如果是数字,则需要判断是否是多位数
				numStr = "";
				while(i < expression.length() && (ch = expression.charAt(i)) >= 48 && (ch = expression.charAt(i)) <= 57) {
					numStr+=ch;
					i++;
				}
				list.add(numStr);
			}
		}while(i < expression.length());//扫描结束
		return list;
	}


//2 运算方法	
public void calculate(List<String> expressionList) {
		//新建一个stack
		Stack<String> stack = new Stack<String>();
		int num1;//操作数
		int num2;
		int res;//运算结果
		//开始扫描
		for (String item : expressionList) {
			if(item.matches("\\d+")) {// \d+表示1个或多个0到9的数字,是整数部分(至少是一位整数的整数部分)
				//直接入栈
				stack.push(item);
			}else {
				//操作符,弹出两位数进行运算,运算结果重新进栈
				num2 = Integer.parseInt(stack.pop());
				num1 = Integer.parseInt(stack.pop());
				res = 0;
				//后缀表达式(逆波兰表达式)是从左向右扫描
				if(item.equals("+")) {
					res = num1 + num2;
				}else if(item.equals("-")) {
					res = num1 - num2;
				}else if(item.equals("*")) {
					res = num1 * num2;
				}else if(item.equals("/")) {
					res = num1 / num2;
				}else {
					throw new RuntimeException("运算符错误");
				}
				stack.push(res+"");
			}
		}
		//循环结束后只剩下运算结果
		System.out.println("运算结果="+stack.pop());
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章