数据结构和算法 Java版本(11)中缀转后缀算法分析与实现

数据结构和算法 Java版本(11)中缀转后缀算法分析与实现

中缀转后缀表达式

具体步骤

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

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

3.遇到操作数,将其压s2;

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

​ 1)如果s1位空,或栈顶运算符位左括号“(”,则直接将此运算符入栈;

​ 2)否则,若优先级比栈顶运算符高,也将运算符压入s1;

​ 3)否则,将s1栈顶的运算符弹出并压入到s2中,再次转到(4-1)与s1中新的栈顶运算符相比较;

5.遇到括号时:

​ 1)如果是左括号“(”,则直接压入s1

​ 2)如果是右括号“)”,则依次弹出s1栈顶的运算符,并压入s2,直到遇到左括号为止,此时将这一对括号丢弃

6.重复步骤2至5,直到表达式的最右边

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

8.依次弹出s2中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C3MXeY6O-1601553266716)(G:\Java数据结构和算法\数据结构和算法(11)中缀转后缀算法分析\QQ图片20201001182820.png)]

完成将中缀表达式转换为后缀表达式

  1. 1+((2+3)*4)-5 => 转成 1 2 3 + 4 * + 5 -

  2. 因为直接对str 进行操作不方便,先将“ 1+((2+3)*4)-5 ”=》 中缀表达式对应的List

  3. “ 1+((2+3)*4)-5 ”=》ArrayList [1,+,(,(,2,+,3,), * ,4,),-,5]

  4. 将得到的中缀表达式对应的List =》后缀表达式对应的List

  5. ArrayList [1,+,(,(,2,+,3,), * ,4,),-,5] => ArrayList [1,2,3,+,4,*,+,5,-]

    代码实现

    package com.mwq.stack;
    
    import java.util.List;
    import java.util.Stack;
    
    
    
    import java.util.ArrayList;
    
    public class PolandNptation {
    
    	public static void main(String[] args) {
    		
    		//完成将一个中缀表达式转成后缀表达式的功能
    		
    		String expression = "1+((2+3)*4)-5";
    		List<String> infixExpressionList = toInfixExpressionList(expression);
    		System.out.println("中缀表达式的List" + infixExpressionList);//[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]
    		List<String> suffixExpressionList = parseSuffixExpressionList(infixExpressionList);
    		System.out.println("后缀表达式的List" + suffixExpressionList);
    		
    		System.out.printf("expression=%d", calculate(suffixExpressionList));//expression=16;
    		
    		/*
    		 
    		// 先定义一个逆波兰表达式
    		//(3+4)*5-6 =>3 4 + 5 6 - 
    		//"4 5 * 8 - 60 + 8 2 / +"
    		//为了说明方便,逆波兰表达式的数字和符号使用空格隔开
    		//String suffixExpression= "30 4 + 5 * 6 -";
    		String suffixExpression= "4 5 * 8 - 60 + 8 2 / +";
    		
    		//思路
    		//1.先将"3 4 + 5 * 6 -" =>放到ArrayList中
    		//2. 将ArrayList 传递一个方法,遍历ArrayList 配合栈,完成计算
    		
    		List<String> List =getListString(suffixExpression);
    		System.out.println("rpnList="+ List);
    		
    		int res = calculate(List);
    		System.out.println("计算的结果是" + res);
    		
    		*/
    	}
    	
    	//方法:将得到的中缀表达式对应的List => 后缀表达式对应的List
    	public static List<String> parseSuffixExpressionList(List<String> ls){
    		//定义两个栈
    		Stack<String> s1 = new Stack<String>(); //符号栈
    		//说明:因为s2这个栈在整个转换过程中没有pop操作,而且后面还需逆序输出
    		//因此我们不用Stack<String>直接使用List<String> s2
    		List<String> s2 = new ArrayList<String>();//储存中间结果的List s2
    		
    		
    		//遍历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("(")) {
    					s2.add(s1.pop());
    				}
    				s1.pop();//!!! 将(弹出s1栈,消除小括号
    			}else {
    				//
    				while(s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {
    					s2.add(s1.pop());
    				}
    				//还需要item压入栈
    				s1.push(item);
    			}
    		}
    		//将s1中剩余的运算符依次弹出并加入s2中
    		while (s1.size() !=0) {
    			s2.add(s1.pop());
    		}
    		return s2;//注意是因为存放到List,因此按顺序输出就是对应的后缀表达式对应的List
    	}
    	
    	
    	
    	
    	//方法:将 中缀表达式转成对应的List
    	//s="1+((2+3)*4)-5";
    	public static List<String> toInfixExpressionList(String s){
    		//定义一个List,存放中缀表达式对应的内容
    		List<String> ls=new ArrayList<String>();
    		int i=0;
    		String str;
    		char c;
    		do {
    			//如果c是非数字,需要加入到ls
    			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中
    	public static List<String> getListString(String suffixExpression){
    		//将一个逆波兰表达式,依次将数据和运算符放入到ArrayList中
    		String[] split = suffixExpression.split(" ");
    		List<String> list = new ArrayList<String>();
    		for(String ele: split) {
    			list.add(ele);
    		}
    		return list;
    	}
        //完成对逆波兰表达式的运算
    	public static int calculate(List<String> ls) {
    		//创建栈,只需要一个栈即可
    		Stack<String> stack = new Stack<String>();
    		//遍历 ls
    		for(String item: ls) {
    			//使用正则表达式取出数
    			if(item.matches("\\d+")) {//匹配多位数
    				//入栈
    				stack.push(item);
    			}else {
    				//pop出两个数,运算,再入栈
    				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);
    			}
    		}
    		//最后留在stack中的数据是运算结果
    		return Integer.parseInt(stack.pop());
    	}
    }
    
    
    //编写一个类 Operation  可以返回一个运算符 对应的优先级
     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 result = 0;
    		 switch (operation) {
    		 case "+":
    			 result = ADD;
    			 break;
    		 case "-":
    			 result = SUB;
    			 break;
    		 case "*":
    			 result = MUL;
    			 break;
    		 case "/":
    			 result = DIV;
    			 break;
    	     default:
    	    	 System.out.println("不存在该运算符");
    	    	 break;
    			 }
    		 return result;
    	 }
     }
    

    结果展示

    中缀表达式的List[1, +, (, (, 2, +, 3, ), *, 4, ), -, 5]
    不存在该运算符
    不存在该运算符
    后缀表达式的List[1, 2, 3, +, 4, *, +, 5, -]
    expression=16
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值