1. package com.atguigu.stack;
    2. import java.util.ArrayList;
    3. import java.util.List;
    4. import java.util.Stack;
    5. /**
    6. * @author Dxkstart
    7. * @create 2021-10-08-19:49
    8. */
    9. public class PolandNotation {
    10. public static void main(String[] args) {
    11. //完成将一个中缀表达式转成后缀表达式的功能
    12. //说明
    13. //1. 1+((2+3)*4)-5 => 转成1 2 3 + 4 * + 5 -
    14. //2.因为直接对str进行操作,不方便,因此先将"1+((2+3)*4)-5" => 中缀的表达式对应的List
    15. // 即 "1+((2+3)*4)-5" => ArrayList[1,+,(,(,2,+,3,),*,4,),-,5]
    16. //3.将得到的中缀表达式对应的list => 后缀表达式对应的List
    17. // 即ArrayList[1,+,(,(,2,+,3,),*,4,),-,5] => ArrayList[1,2,3,+,4,*,+,5,-]
    18. String expression = "1+((2+3)*4)-5";
    19. List<String> list = toInfixExpressionList(expression);//返回中缀表达式的list
    20. System.out.println("中缀表达式的list: " + list);
    21. List<String> suffixExpression = parseSuffixExpression(list);//返回后缀表达式
    22. System.out.println("后缀表达式的list: " + suffixExpression);
    23. //计算
    24. int value = calculate(suffixExpression);
    25. System.out.println("计算结果为:" + value);
    26. //先定义一个逆波兰表达式
    27. //(3+4)*5-6 => 3 4 + 5 * 6 -
    28. // String suffixExpression = "3 4 + 5 * 6 -";
    29. //思路
    30. //1.先将 "3 4 + 5 * 6 -" => 放到ArrayList中
    31. //2.将ArrayList传递给一个方法,遍历ArrayList配合栈完成计算
    32. // List<String> rpnList = getListString(str);
    33. //
    34. //
    35. // System.out.println("计算结果为:" + calculate(rpnList));
    36. }
    37. //方法:将中缀表达式转成对应的List
    38. public static List<String> toInfixExpressionList(String s) {
    39. //定义一个List,存放中缀表达式对应的内容
    40. List<String> ls = new ArrayList();
    41. int i = 0;//这时是一个指针,用于遍历中缀表达式字符串
    42. String str;//对多位数拼接
    43. char c;//没遍历到一个字符,就放入到c
    44. do {
    45. //如果c是一个非数字,就需要加入到list中
    46. if ((c = s.charAt(i)) < 48 || (c = s.charAt(i)) > 57) {
    47. ls.add("" + c);
    48. i++;//i需要后移
    49. } else {//如果是数字,需要考虑多位数
    50. str = "";//先将str置为"", '0'=48, '9'=57
    51. while (i < s.length() && (c = s.charAt(i)) >= 48 && (c = s.charAt(i)) <= 57) {
    52. str += c;//拼接
    53. i++;
    54. }
    55. ls.add(str);
    56. }
    57. } while (i < s.length());
    58. return ls;
    59. }
    60. // 即ArrayList[1,+,(,(,2,+,3,),*,4,),-,5] => ArrayList[1,2,3,+,4,*,+,5,-]
    61. //方法:将得到的中缀表达式对应的list => 后缀表达式对应的List
    62. public static List<String> parseSuffixExpression(List<String> ls) {
    63. //定义两个栈
    64. Stack<String> s1 = new Stack<>();//符号栈
    65. //因为s2这个栈,在整个转换过程中,没有pop操作,而且后面我们还要逆序输出
    66. //因此比较麻烦,这里我们就不用栈了,直接使用List<String> s2
    67. //Stack<String> s2 = new Stack<>();//储存中间结果的栈s2
    68. ArrayList<String> s2 = new ArrayList<>();
    69. //遍历ls
    70. for (String item : ls) {
    71. //如果是一个数,加入s2
    72. if (item.matches("\\d+")) {//如果是一个数字(包含多位数)
    73. s2.add(item);
    74. } else if (item.equals("(")) {
    75. s1.push(item);
    76. } else if (item.equals(")")) {
    77. while (!s1.peek().equals("(")) {//peek(),查看栈顶元素
    78. s2.add(s1.pop());
    79. }
    80. s1.pop();//!将s1中的( 弹出,以此消除了一对括号。
    81. } else {
    82. //当item的优先级小于等于s1栈顶运算符,将s1栈顶的运算符弹出并加入到s2中,再次转到上一步(4.1),
    83. // 与s1中新的栈顶运算符相比较
    84. //比较运算符优先级的方法Operation类中的getValue()
    85. while (s1.size() != 0 && Operation.getValue(s1.peek()) >= Operation.getValue(item)) {
    86. s2.add(s1.pop());
    87. }
    88. //还需要将item压入栈
    89. s1.push(item);
    90. }
    91. }
    92. //将s1中剩余的运算符弹出加入到s2中
    93. while (s1.size() != 0) {
    94. s2.add(s1.pop());
    95. }
    96. return s2;//注意:因为存放到List,因此按顺序输出就是对应的后缀表达式
    97. }
    98. //************************************************
    99. //将一个逆波兰表达式,依次将数据和运算符放入到ArrayList中
    100. public static List<String> getListString(String suffixExpression) {
    101. //将sufferExpression 分割
    102. String[] split = suffixExpression.split(" ");
    103. List<String> list = new ArrayList<>();
    104. for (String str : split) {
    105. list.add(str);
    106. }
    107. return list;
    108. }
    109. //完成对逆波兰表达式的运算
    110. /*
    111. 1.从左至右扫描,将3和4压入堆栈
    112. 2.遇到+运算符,因此弹出4和3(4为栈顶元素,3为次顶元素),计算出3+4的值,得7,再将7入栈
    113. 3.将5入栈
    114. 4.接下来是×运算符,因此弹出5和7,计算出7*5=35,将35入栈
    115. 5.将6入栈
    116. 6.最后是-运算符,计算出35-6的值,即29,由此得出最终结果
    117. */
    118. public static int calculate(List<String> ls) {
    119. int val;
    120. int num2;
    121. int num1;
    122. //创建一个栈,只需要一个就可以
    123. Stack<String> stack = new Stack<>();
    124. //遍历ls
    125. for (String item : ls) {
    126. //这里用正则表达式来判断取出来的是数字还是符号
    127. if (item.matches("\\d+")) { //匹配的是多位数
    128. //入栈
    129. stack.push(item);
    130. } else {
    131. //pop出两个数,并运算,再将结果入栈
    132. num2 = Integer.parseInt(stack.pop());
    133. num1 = Integer.parseInt(stack.pop());
    134. if (item.equals("+")) {
    135. val = num1 + num2;
    136. } else if (item.equals("-")) {
    137. val = num1 - num2;
    138. } else if (item.equals("*")) {
    139. val = num1 * num2;
    140. } else if (item.equals("/")) {
    141. val = num1 / num2;
    142. } else {
    143. throw new RuntimeException("运算符有误!");
    144. }
    145. //把val入栈
    146. stack.push(Integer.toString(val));
    147. }
    148. }
    149. return Integer.parseInt(stack.pop());
    150. }
    151. }
    152. //编写一个类Operation 可以返回一个运算符对应的优先级
    153. class Operation {
    154. private static final int ADD = 1;// +
    155. private static final int SUB = 1;// -
    156. private static final int MUL = 2;// *
    157. private static final int DIV = 2;// /
    158. //写一个方法,返回对应的优先级数字
    159. public static int getValue(String operation) {
    160. int result = 0;
    161. switch (operation) {
    162. case "+":
    163. result = ADD;
    164. break;
    165. case "-":
    166. result = SUB;
    167. break;
    168. case "*":
    169. result = MUL;
    170. break;
    171. case "/":
    172. result = DIV;
    173. break;
    174. }
    175. return result;
    176. }
    177. }