• 前缀,后缀表达式(逆波兰表达式),中缀表达式转为对应的后缀表达式,逆波兰计算器的实现(java)


    1.前缀表达式(波兰表达式)

    1.前缀表达式的定义

    前缀表达式的运算符位于操作符之前
    例如:(3+4)*5-6对应的前缀表达式就是 - * + 3 4 5 6

    2.前缀表达式的计算机求值
    从右至左扫描表达式,遇到数字时就将数字压入堆栈,遇到运算符时弹出栈顶的两个数,用运算符对它们做相应的计算(栈顶元素和次顶元素),并将结果入栈;重复上述过程知道表达式最左端,最后运算得出的值即为表达式的结果

    举例:
    (3+4)*5-6对应的前缀表达式就是 - * + 3 4 5 6,针对前缀表达式求值步骤如下:

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

    中缀表达式就是我们常见的表达式,
    比如:(3+4)*5-6

    2.后缀表达式(逆波兰表达式)

    后缀表达式定义:运算符位于操作符之后
    举例:
    (3+4)*5-6对应的后缀表达式就是 3 4 + 5 * 6 -
    在这里插入图片描述
    后缀表达式的计算机求值
    从左至右扫描表达式,遇到数字将数字压入栈中,遇到运算符时弹出栈顶的两个数,用运算符对它们做相应的计算(次顶元素和栈顶元素),并将结果入栈;重复上述过程知道表达式最右端,最后运算得出的值即为表达式的结果

    例如:
    (3+4)*5-6对应的前缀表达式就是 - * + 3 4 5 6,针对前缀表达式求值步骤如下:

    1. 从左到右扫描,将3和4压入栈中
    2. 遇到+运算符,弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈
    3. 将5入栈
    4. 接下来是运算符,由此弹出5和7,计算75=35,将35入栈
    5. 将6入栈
    6. 最后是 - 运算符,计算出35-6的值29,得出最终结果

    3.完成一个简易版的逆波兰计算器

    要求:
    输入一个逆波兰表达式(后缀表达式),使用栈(stack),计算其结果

    思路分析如上
    后缀表达式的计算机求值

    代码实现:

    	//完成对逆波兰表达式的运算
    	/*
    	 * 1)从左至右扫描,将3和4压入堆栈;
    		2)遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈;
    		3)将5入栈;
    		4)接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
    		5)将6入栈;
    		6)最后是-运算符,计算出35-6的值,即29,由此得出最终结果
    	 */
    	
    	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());
    	}
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    4.中缀表达式转为后缀表达式

    中缀表达式转后缀表达式思路分析

    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中的元素并输出,结果的逆序即为中缀表达式对应的后缀表达式

    举例说明:
    将中缀表达式“1+((2+3)*4)-5”转为后缀表达式的过程如下

    举例
    其结果为123+4*+5-

    5.完整逆波兰计算器的实现

    代码实现:

    import java.util.ArrayList;
    import java.util.List;
    import java.util.Stack;
    
    public class PolandNotation {
    
    	public static void main(String[] args) {
    		//完成将一个中缀表达式转成后缀表达式的功能
    		//说明
    		//1. 1+((2+3)×4)-5 => 转成  1 2 3 + 4 × + 5 –
    		//2. 因为直接对str 进行操作,不方便,因此 先将  "1+((2+3)×4)-5" =》 中缀的表达式对应的List
    		//   即 "1+((2+3)×4)-5" => ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]
    		//3. 将得到的中缀表达式对应的List => 后缀表达式对应的List
    		//   即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]  =》 ArrayList [1,2,3,+,4,*,+,5,–]
    		
    		String expression = "1+((2+3)*4)-5";//注意表达式 
    		List<String> infixExpressionList = toInfixExpressionList(expression);
    		System.out.println("中缀表达式对应的List=" + infixExpressionList); 
    		// ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]
    		List<String> suffixExpreesionList = parseSuffixExpreesionList(infixExpressionList);
    		System.out.println("后缀表达式对应的List" + suffixExpreesionList); 
    		//ArrayList [1,2,3,+,4,*,+,5,–] 
    		
    		System.out.printf("expression=%d", calculate(suffixExpreesionList)); 
    		
    	}
    	//即 ArrayList [1,+,(,(,2,+,3,),*,4,),-,5]  =》 ArrayList [1,2,3,+,4,*,+,5,–]
    	//方法:将得到的中缀表达式对应的List => 后缀表达式对应的List
    	public static List<String> parseSuffixExpreesionList(List<String> ls) {
    		//定义两个栈
    		Stack<String> s1 = new Stack<String>(); // 符号栈
    		//说明:因为s2 这个栈,在整个转换过程中,没有pop操作,而且后面我们还需要逆序输出
    		//因此比较麻烦,这里我们就不用 Stack 直接使用 List s2
    		//Stack s2 = new Stack(); // 储存中间结果的栈s2
    		List<String> s2 = new ArrayList<String>(); // 储存中间结果的Lists2
    		
    		//遍历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 {
    				//当item的优先级小于等于s1栈顶运算符, 
    				//将s1栈顶的运算符弹出并加入到s2中,
    				//再次转到(4.1)与s1中新的栈顶运算符相比较
    				//问题:我们缺少一个比较优先级高低的方法
    				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());
    		}
            //注意因为是存放到List, 
            //因此按顺序输出就是对应的后缀表达式对应的List
    		return s2; 
    		
    	}
    	
    	//方法:将 中缀表达式转成对应的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; // 每遍历到一个字符,就放入到c
    		do {
    			//如果c是一个非数字,我需要加入到ls
    			if((c=s.charAt(i)) < 48 ||  (c=s.charAt(i)) > 57) {//ASCII码
    				ls.add("" + c);
    				i++; //i需要后移
    			} else { //如果是一个数,需要考虑多位数
    				str = ""; //先将str 置成"" '0'[48]->'9'[57]
    				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) {
    		//将 suffixExpression 分割,以空格来分割
    		String[] split = suffixExpression.split(" ");
    		List<String> list = new ArrayList<String>();
    		for(String ele: split) {
    			list.add(ele);
    		}
    		return list;
    		
    	}
    	
    	//完成对逆波兰表达式的运算
    	/*
    	 * 1)从左至右扫描,将3和4压入堆栈;
    		2)遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),
    		计算出3+4的值,得7,再将7入栈;
    		3)将5入栈;
    		4)接下来是×运算符,因此弹出5和7,计算出7×5=35,将35入栈;
    		5)将6入栈;
    		6)最后是-运算符,计算出35-6的值,即29,由此得出最终结果
    	 */
    	
    	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("不存在该运算符" + operation);
    			break;
    		}
    		return result;
    	}
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188

    本篇博客参考内容

  • 相关阅读:
    Linux之父一语成谶:Valve拯救桌面版Linux,但新版本仍在分裂其生态
    神级开源库收藏
    软件测试工具常用的都有哪些
    java计算机毕业设计ssm高校会议预约系统(源码+系统+mysql数据库+Lw文档)
    Java面向对象学习笔记-4
    Teams Tab App 代码深入浅出 - 配置页面
    深入探索C与C++的混合编程
    编程题01——十进制转二进制
    垃圾回收调优(GC调优)
    二分查找算法合集
  • 原文地址:https://blog.csdn.net/m0_57105290/article/details/124115831