Advertisement
Guest User

Untitled

a guest
Jan 18th, 2017
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.04 KB | None | 0 0
  1. /**
  2. * Created by daniel on 18.01.17.
  3. */
  4. import java.math.BigDecimal;
  5. import java.util.*;
  6.  
  7. /**
  8. * Класс содержит утилиты для разбора и обработки математических выражений.
  9. *
  10. * @author Борис Марченко
  11. * @version $Revision$ $Date$
  12. */
  13. public class Main {
  14. /**
  15. * Основные математические операции и их приоритеты.
  16. *
  17. * @see #sortingStation(String, java.util.Map)
  18. */
  19. public static final Map<String, Integer> MAIN_MATH_OPERATIONS;
  20.  
  21. static {
  22. MAIN_MATH_OPERATIONS = new HashMap<String, Integer>();
  23. MAIN_MATH_OPERATIONS.put("*", 1);
  24. MAIN_MATH_OPERATIONS.put("/", 1);
  25. MAIN_MATH_OPERATIONS.put("+", 2);
  26. MAIN_MATH_OPERATIONS.put("-", 2);
  27. }
  28.  
  29. /**
  30. * Преобразует выражение из инфиксной нотации в обратную польскую нотацию (ОПН) по алгоритму <i>Сортировочная
  31. * станция</i> Эдскера Дейкстры. Отличительной особенностью обратной польской нотации является то, что все
  32. * аргументы (или операнды) расположены перед операцией. Это позволяет избавиться от необходимости использования
  33. * скобок. Например, выражение, записаное в инфиксной нотации как 3 * (4 + 7), будет выглядеть как 3 4 7 + *
  34. * в ОПН. Символы скобок могут быть изменены.
  35. * <a href="http://ru.wikipedia.org/wiki/Обратная_польская_запись">Подробнее об ОПЗ</a>.
  36. *
  37. * @param expression выражение в инфиксной форме.
  38. * @param operations операторы, использующиеся в выражении (ассоциированные, либо лево-ассоциированные).
  39. * Значениями карты служат приоритеты операции (самый высокий приоритет - 1). Например, для 5
  40. * основных математических операторов карта будет выглядеть так:
  41. * <pre>
  42. * * -> 1
  43. * / -> 1
  44. * + -> 2
  45. * - -> 2
  46. * </pre>
  47. * Приведенные операторы определены в константе {@link #MAIN_MATH_OPERATIONS}.
  48. * @param leftBracket открывающая скобка.
  49. * @param rightBracket закрывающая скобка.
  50. * @return преобразованное выражение в ОПН.
  51. */
  52. public static String sortingStation(String expression, Map<String, Integer> operations, String leftBracket,
  53. String rightBracket) {
  54. if (expression == null || expression.length() == 0)
  55. throw new IllegalStateException("Expression isn't specified.");
  56. if (operations == null || operations.isEmpty())
  57. throw new IllegalStateException("Operations aren't specified.");
  58. // Выходная строка, разбитая на "символы" - операции и операнды..
  59. List<String> out = new ArrayList<String>();
  60. // Стек операций.
  61. Stack<String> stack = new Stack<String>();
  62.  
  63. // Удаление пробелов из выражения.
  64. expression = expression.replace(" ", "");
  65.  
  66. // Множество "символов", не являющихся операндами (операции и скобки).
  67. Set<String> operationSymbols = new HashSet<String>(operations.keySet());
  68. operationSymbols.add(leftBracket);
  69. operationSymbols.add(rightBracket);
  70.  
  71. // Индекс, на котором закончился разбор строки на прошлой итерации.
  72. int index = 0;
  73. // Признак необходимости поиска следующего элемента.
  74. boolean findNext = true;
  75. while (findNext) {
  76. int nextOperationIndex = expression.length();
  77. String nextOperation = "";
  78. // Поиск следующего оператора или скобки.
  79. for (String operation : operationSymbols) {
  80. int i = expression.indexOf(operation, index);
  81. if (i >= 0 && i < nextOperationIndex) {
  82. nextOperation = operation;
  83. nextOperationIndex = i;
  84. }
  85. }
  86. // Оператор не найден.
  87. if (nextOperationIndex == expression.length()) {
  88. findNext = false;
  89. } else {
  90. // Если оператору или скобке предшествует операнд, добавляем его в выходную строку.
  91. if (index != nextOperationIndex) {
  92. out.add(expression.substring(index, nextOperationIndex));
  93. }
  94. // Обработка операторов и скобок.
  95. // Открывающая скобка.
  96. if (nextOperation.equals(leftBracket)) {
  97. stack.push(nextOperation);
  98. }
  99. // Закрывающая скобка.
  100. else if (nextOperation.equals(rightBracket)) {
  101. while (!stack.peek().equals(leftBracket)) {
  102. out.add(stack.pop());
  103. if (stack.empty()) {
  104. throw new IllegalArgumentException("Unmatched brackets");
  105. }
  106. }
  107. stack.pop();
  108. }
  109. // Операция.
  110. else {
  111. while (!stack.empty() && !stack.peek().equals(leftBracket) &&
  112. (operations.get(nextOperation) >= operations.get(stack.peek()))) {
  113. out.add(stack.pop());
  114. }
  115. stack.push(nextOperation);
  116. }
  117. index = nextOperationIndex + nextOperation.length();
  118. }
  119. }
  120. // Добавление в выходную строку операндов после последнего операнда.
  121. if (index != expression.length()) {
  122. out.add(expression.substring(index));
  123. }
  124. // Пробразование выходного списка к выходной строке.
  125. while (!stack.empty()) {
  126. out.add(stack.pop());
  127. }
  128. StringBuffer result = new StringBuffer();
  129. if (!out.isEmpty())
  130. result.append(out.remove(0));
  131. while (!out.isEmpty())
  132. result.append(" ").append(out.remove(0));
  133.  
  134. return result.toString();
  135. }
  136.  
  137. /**
  138. * Преобразует выражение из инфиксной нотации в обратную польскую нотацию (ОПН) по алгоритму <i>Сортировочная
  139. * станция</i> Эдскера Дейкстры. Отличительной особенностью обратной польской нотации является то, что все
  140. * аргументы (или операнды) расположены перед операцией. Это позволяет избавиться от необходимости использования
  141. * скобок. Например, выражение, записаное в инфиксной нотации как 3 * (4 + 7), будет выглядеть как 3 4 7 + *
  142. * в ОПН.
  143. * <a href="http://ru.wikipedia.org/wiki/Обратная_польская_запись">Подробнее об ОПЗ</a>.
  144. *
  145. * @param expression выражение в инфиксной форме.
  146. * @param operations операторы, использующиеся в выражении (ассоциированные, либо лево-ассоциированные).
  147. * Значениями карты служат приоритеты операции (самый высокий приоритет - 1). Например, для 5
  148. * основных математических операторов карта будет выглядеть так:
  149. * <pre>
  150. * * -> 1
  151. * / -> 1
  152. * + -> 2
  153. * - -> 2
  154. * </pre>
  155. * Приведенные операторы определены в константе {@link #MAIN_MATH_OPERATIONS}.
  156. * @return преобразованное выражение в ОПН.
  157. */
  158. public static String sortingStation(String expression, Map<String, Integer> operations) {
  159. return sortingStation(expression, operations, "(", ")");
  160. }
  161.  
  162. /**
  163. * Вычисляет значение выражения, записанного в инфиксной нотации. Выражение может содержать скобки, числа с
  164. * плавающей точкой, четыре основных математических операндов.
  165. *
  166. * @param expression выражение.
  167. * @return результат вычисления.
  168. */
  169. public static BigDecimal calculateExpression(String expression) {
  170. String rpn = sortingStation(expression, MAIN_MATH_OPERATIONS);
  171. StringTokenizer tokenizer = new StringTokenizer(rpn, " ");
  172. Stack<BigDecimal> stack = new Stack<BigDecimal>();
  173. while (tokenizer.hasMoreTokens()) {
  174. String token = tokenizer.nextToken();
  175. // Операнд.
  176. if (!MAIN_MATH_OPERATIONS.keySet().contains(token)) {
  177. stack.push(new BigDecimal(token));
  178. } else {
  179. BigDecimal operand2 = stack.pop();
  180. BigDecimal operand1 = stack.empty() ? BigDecimal.ZERO : stack.pop();
  181. if (token.equals("*")) {
  182. stack.push(operand1.multiply(operand2));
  183. } else if (token.equals("/")) {
  184. stack.push(operand1.divide(operand2));
  185. } else if (token.equals("+")) {
  186. stack.push(operand1.add(operand2));
  187. } else if (token.equals("-")) {
  188. stack.push(operand1.subtract(operand2));
  189. }
  190. }
  191. }
  192. if (stack.size() != 1)
  193. throw new IllegalArgumentException("Expression syntax error.");
  194. return stack.pop();
  195. }
  196.  
  197. private Main() {
  198. }
  199.  
  200. public static void main(String[] args) {
  201. String expression = "(1 + 2) * 4 + 3";
  202. String rpn = sortingStation(expression, MAIN_MATH_OPERATIONS);
  203. System.out.println("\tРезультат " + calculateExpression(expression));
  204. }
  205. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement