前缀、中缀、后缀表达式

前缀表达式:波兰表达式(运算符位于数字之前)

(3+4)×5-6的前缀表达式是 : -×+3456

针对前缀表达式求值结果:

  1. 从右至左扫描,将6、5、4、3压入堆栈
  2. 遇到+运算符,弹出3和4(3为栈顶元素、4为次顶元素),计算3+4=7,将7压入堆栈
  3. 接下来是×运算符,弹出7和5,计算7×5=35,将35入栈
  4. 最后是-运算符,计算出35(次顶)-6(栈顶)的值为29

中缀表达式:如(3+4)×5-6

计算机不好操作中缀表达式,常将中缀表达式变成后缀表达式

(3+4)×5-6的后缀表达式是 : 3、4+5×6-

针对后缀表达式求值结果:

  1. 从左至右扫描,将3和4压入堆栈
  2. 遇到+运算符,弹出3和4(3为栈顶元素、4为次顶元素),计算3+4=7,将7压入堆栈
  3. 将5入栈
  4. 接下来是×运算符,弹出7和5,计算7×5=35,将35入栈
  5. 将6入栈
  6. 最后是-运算符,计算出35(栈顶)-6(次顶)的值为29

**逆波兰计算器:**输入逆波兰表达式,使用栈实现

中缀表达式转后缀表达式步骤:

  1. 初始化两个栈:运算符栈s1,和储存中间结果的栈s2

  2. 从左至右扫描中缀表达式

  3. 遇到操作数压入s2

  4. 遇到运算符,比较与s1栈顶运算符的优先级

    1. 如果s1为空,或栈顶运算符为”(“,则直接将此运算符入栈
    2. 否则,若运算符优先级比s1栈顶高,也将运算符压入s1
    3. 否则,将s1栈顶的运算符弹出并压入s2中,再次转到4.1与s1新的栈顶元素比较
  5. 遇到括号时:

    1. 如果是”(“,则直接压入s1
    2. 如果是”)“,则依次弹出s1栈顶的运算符,并压入s2,直到遇到”(“为止,将这一对括号丢弃
  6. 重复步骤2~5,直到表达式最右边

  7. 将s1中剩余的运算符依次弹出并压入s2

  8. 依次弹出s2中的元素并输出,**结果的逆序即为中缀表达式对应的后缀表达式
    在这里插入图片描述

package dk.hello;

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

public class PolandNotation {

	public static void main(String[] args) {
		
		//将中缀表达式1+((2+3)*4)-5转成后缀表达式1 2 3 + 4 * + 5 -
		//对str操作不方便,将中缀表达式转化成ArrayList[1,+,(,(,2,+,3,),*,4,),-,5]
		String expression = "1+((2+3)*4)-5";
		List<String> infixExpressionList = toInfixExpressionList(expression);
		System.out.println(infixExpressionList);
		
		//将得到的中缀表达式ArrayList转成后缀表达式
		List<String> parseSuffixExpressionList = parseSuffixExpressionList(infixExpressionList);
		System.out.println(parseSuffixExpressionList);
		
		
		//先定义逆波兰表达式,用空格隔开
		String suffixExpression = "3 4 + 5 * 6 -";
		//1.将sufferixExpression放到ArrayList
		//2.将ArrayList传入方法,遍历配合栈运算
		
		List<String> rpnlist = getListString(suffixExpression);
		System.out.println(rpnlist);
		
		int res = calculate(rpnlist);
		System.out.println(res);
		
		
	}
	
	//将中缀表达式转成ArrayList,s=1+((2+3)*4)-5
	public static List<String> toInfixExpressionList(String s){
		List<String> ls = new ArrayList<String>();
		int i = 0;     //指针用于遍历中缀表达式字符串
		String str;    //对多位数拼接
		char c;        //每遍历一个字符就放到c
		do {
			if ((c=s.charAt(i)) < 48 || (c=s.charAt(i)) > 57) {   //非数字
				ls.add("" + c);
				i++;       //i需要后移
			}else {     //如果是数字需要考虑多位数的问题
				str = "";   //先将str置为空串
				while (i < s.length() && ((c=s.charAt(i)) >= 48 || (c=s.charAt(i)) <= 57)) {
					str += c;
					i++;
				}
				ls.add(str);   //将数字加入数组
			}
		} while (i < s.length());
		return ls;
	}
	
	//将ArrayList[1,+,(,(,2,+,3,),*,4,),-,5]转成ArrayList[1 2 3 + 4 * + 5 -]
	public static List<String> parseSuffixExpressionList(List<String> ls){
		//定义两个栈
		Stack<String> s1 = new Stack<String>();  //符号栈
		//因为s2栈在转化过程中没有pop操作,就不用stack,就用list
		//Stack<String> s2 = new Stack<String>();
		List<String> s2 = new ArrayList<String>();
		//遍历ls
		for (String item : ls) {
			//如果是一个数就入s2栈
			if (item.matches("\\d+")) {        //是一个数
				s2.add(item);
			}else if (item.equals("(")) {
				s1.push(item);
			}else if (item.equals(")")) {
				//如果是”)“,则依次弹出s1栈顶的运算符,并压入s2,直到遇到”(“为止,将这一对括号丢弃
				while (!s1.peek().equals("(")) {   //peek查看栈顶的元素
					s2.add(s1.pop());
				}
				s1.pop();//将”(“弹出s1栈
			}else {
				//当item的优先级小于等于s1栈顶运算符,将s1栈顶的运算符弹出并加入s2中,再次转到4.1与s1新的栈顶元素比较
				while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {
					s2.add(s1.pop());
				}
				//还需要将item压入s1
				s1.push(item);
			}
		}
		//将s1中剩余的运算符依次弹出并压入s2
		while (s1.size() != 0) {
			s2.add(s1.pop());
		}
		//按顺序输出s2就是逆序输出栈
		return s2;
	}
	
	//将逆波兰表达式依次将数据和运算符放入ArrayList
	public static List<String> getListString(String suffixExpression){
		String[] split = suffixExpression.split(" ");  //将suffixExpression分割
		List<String> list = new ArrayList<String>();
		for (String ele : split) {
			list.add(ele);
		}
		return list;
	}

	//完成对逆波兰表达式运算
	//1. 从左至右扫描,将3和4压入堆栈
	//2. 遇到+运算符,弹出3和4(3为栈顶元素、4为次顶元素),计算3+4=7,将7压入堆栈
	//3. 将5入栈
	//4. 接下来是×运算符,弹出7和5,计算7×5=35,将35入栈
	//5. 将6入栈
	//6. 最后是-运算符,计算出35(栈顶)-6(次顶)的值为29
	public static int calculate(List<String> ls) {
		//创建栈
		Stack<String> stack = new Stack<String>();
		for (String item : ls) {
			//使用正则表达式取出数
			if (item.matches("//d+")) {     //匹配的是多位数直接入栈
				stack.push(item);
			}else {          //是符号
				int num2 = Integer.parseInt(stack.pop());
				int num1 = Integer.parseInt(stack.pop());
				int 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("运算符有误");
				}
				//把res入栈
				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 getValue(String operation) {
		int res = 0; // 存放计算结果
		switch (operation) {
		case "*":
			res = MUL;
			break;
		case "/":
			res = DIV; 
			break;
		case "+":
			res = ADD;
			break;
		case "-":
			res = SUB; 
			break;
		default:
			System.out.println("不能存在该运算符");
			break;
		}
		return res;
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了回答你的问题,我将介绍前缀中缀后缀表达式,并展示如何在它们之间进行转换。 1. 前缀表达式(也称为波兰式): 在前缀表达式中,运算符位于操作数之前。例如,表达式 "2 + 3" 的前缀形式为 "+ 2 3"。 2. 中缀表达式: 中缀表达式是我们通常使用的常规数学表达式形式。它使用括号和运算符的优先级来表示运算顺序。例如,表达式 "2 + 3" 就是一个中缀表达式。 3. 后缀表达式(也称为逆波兰式): 在后缀表达式中,运算符位于相应的操作数之后。例如,表达式 "2 + 3" 的后缀形式为 "2 3 +"。 现在,我将向你展示如何将中缀表达式转换为前缀后缀表达式。 从中缀前缀转换: 1. 反转中缀表达式。 2. 将反转的中缀表达式转换为后缀形式。 3. 反转后缀表达式即可得到前缀表达式。 从中缀到后缀转换: 1. 创建一个空栈和一个空输出列表。 2. 从左到右扫描中缀表达式的每个符号。 - 如果遇到操作数,将其添加到输出列表。 - 如果遇到运算符,将其压入栈中。 - 如果遇到左括号,将其压入栈中。 - 如果遇到右括号,则连续弹出栈顶元素并将其添加到输出列表,直到遇到左括号为止。注意:左括号不会被添加到输出列表中。 如果栈顶元素是左括号,则将其弹出栈。 - 如果遇到的运算符具有比栈顶运算符更高的优先级,将其压入栈中。 如果遇到的运算符具有与栈顶运算符相同的优先级,并且是左结合的运算符,则将栈顶运算符弹出并添加到输出列表中,然后将当前运算符压入栈中。 如果遇到的运算符具有与栈顶运算符相同的优先级,并且是右结合的运算符,则将当前运算符压入栈中。 - 重复步骤2直到扫描完整个中缀表达式。 3. 将栈中剩余的所有运算符弹出并添加到输出列表中。 4. 输出列表即为转换后的后缀表达式。 希望这个解释对你有帮助!如果你有其他问题,可以继续问我。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值