zcq

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