// добавление левого потомка public void addLeftChild(BinaryTree element) { if (element != null) { left = element; } }
// добавление правого потомка public void addRightChild(BinaryTree element) { if (element != null) { right = element; } }
// считает кол-во минусов private void countMinus(BinaryTree tree) { List<SignPriority> list = findAllSignes(tree); // найдем все знаки в дереве for (int i = 0; i < list.Count; i++) if (list[i].getSign().Equals("-") && list[i].isPriority()) CountMinus++; }
// добавление потомков private void addChilds(BinaryTree tree, String sign, int pos) { String tmp = tree.getData(); tree.setData(sign); BinaryTree left = new BinaryTree(); // добавление левого потомка left.setData(tmp.Substring(0, pos)); tree.addLeftChild(left); BinaryTree right = new BinaryTree(); // добавление правого потомка right.setData(tmp.Substring(pos + 1)); tree.addRightChild(right); }
// добавление к дереву триг функции private void parseTrigFunction(BinaryTree tree, int pos) { String tmp = tree.getData(); BinaryTree left = new BinaryTree(); tree.setData(tmp.Substring(pos, 3)); // триг функцию добавляем в вершину left.setData(tmp.Substring(pos + 3)); // а аргумент в левого потомка tree.addLeftChild(left); parse(tree.getLeft()); // парсим левого потомка }
// добавление потомков и последующий парсинг левого и правого потомков private void parseNext(BinaryTree tree, String sign, int pos) { addChilds(tree, sign, pos); parse(tree.getLeft()); parse(tree.getRight()); }
// парсинг мат функции, содержащей тригонометрические функции private void parseMathFunction(BinaryTree tree) { if (tree != null) { List<SignPriority> list = findAllSignes(tree); // находим знаки SignPriority sp = sort(tree, list); // сортируем их по приоритетам int pos = 0; if (sp != null) { pos = sp.getPos(); String sign = sp.getSign(); parseNext(tree, sign, pos); } else { pos = findPosMathFunction(tree); parseTrigFunction(tree, pos); } } }
// подсчет кол-ва переменных в дереве private void getCountVariables(BinaryTree tree) { if (tree.getLeft() != null) getCountVariables(tree.getLeft()); if (tree.getRight() != null) getCountVariables(tree.getRight()); if (isVariable(tree.getData()) && !isMathFunction(tree.getData())) { for (int i = 0; i < var.Count; i++) { if (var[i].Equals(tree.getData())) // если такая переменная уже была посчитана { return; } } var.Add(tree.getData()); // иначе добавляем ее } }
// удаление скобочек private void deleteBrackets(BinaryTree tree, String sign) { StringBuilder tmp = new StringBuilder(tree.getData()); if (sign.Equals("(")) tmp = tmp.Remove(tree.getData().IndexOf("("), 1); else if (sign.Equals(")")) tmp = tmp.Remove(tree.getData().LastIndexOf(")"), 1); tree.setData(tmp.ToString()); }
// сортировка пузырьком ариф знаков входной функции private SignPriority sort(BinaryTree tree, List<SignPriority> list) { if (list.Count == 0) return null; else { for (int i = 0; i < list.Count - i - 1; i++) for (int j = 0; j < list.Count - 1; j++) if (compareTo(list, j)) swap(list, j, j + 1); countMinus(tree); // считаем кол-во минусов if (CountMinus > 1) { // нахождение самого последнего приоритетного минуса SignPriority tmp = new SignPriority(); int pos = 0, maxPos = 0; for (int i = 0; i < list.Count; i++) { if (list[i].getSign().Equals("-")) { pos = list[i].getPos(); if (pos > maxPos) { maxPos = pos; tmp = list[i]; } } } CountMinus = 0; return tmp; } return list[0]; } }
// поиск мат знака private void findMathSign(BinaryTree tree, String sign) { int pos = 0; if (tree != null) { if (tree.getLeft() == null && tree.getRight() == null) { if (sign.Equals("-") && CountMinus > 1) // если - и их больше 1 { pos = tree.getData().LastIndexOf(sign); CountMinus--; } else pos = tree.getData().IndexOf(sign); if (pos != -1 && !isVariable(tree.getData()) && !isDigit(tree.getData())) parseNext(tree, sign, pos); } else if (tree.getLeft() != null && tree.getRight() != null) { findMathSign(tree.getLeft(), sign); findMathSign(tree.getRight(), sign); } else throw new Exception("Ошибка при построении дерева!"); } }
private BinaryTree right; // правый потомок #endregion Fields #region Constructors // конструктор public BinaryTree() { data = ""; left = null; right = null; }
// вычисление узла дерева private Double calculate(BinaryTree tree, List<double> args) { double tmp = 0; if (isSign(tree.getData())) // если это знак { tmp = calculateTree(tree, args); // то вычисляем поддерево } else if (isVariable(tree.getData())) // если переменная, то заменяем ее на соответствущее ей входное значение { for (int i = 0; i < var.Count; i++) { if (var[i].Equals(tree.getData())) { tmp = args[i]; break; } } } else if (isDigit(tree.getData())) // если число, то парсим его { tmp = double.Parse(tree.getData()); } return tmp; }
private List<string> var = new List<string>(); // массив переменных #endregion Fields #region Constructors // конструктор класса public CalculationTree(BinaryTree tree) { this.tree = tree; getCountVariables(tree); // подсчет кол-ва переменных }
// добавляет нули вместо пустой строки в дереве разбора private void setZero(BinaryTree tree) { if (tree.getLeft() != null) setZero(tree.getLeft()); if (tree.getRight() != null) setZero(tree.getRight()); if (tree.getData().Equals("")) tree.setData("0"); }
// упрощение функции private void simplifyFunction(BinaryTree tree) { String function = tree.getData(); bool check = false; int battery = 0; int pos = 0; List<SignPriority> list = findAllSignes(tree); // находим все знаки //System.out.println(list); SignPriority sp = sort(tree, list); // сортируем их if (sp != null) { // если есть приоритеный знак pos = sp.getPos(); for (int i = 0; i < pos; i++) // считаем кол-во скобочек { if (function[i] == '(') battery++; else if (function[i] == ')') battery--; } if (pos != -1) { for (int i = pos; i < function.Length; i++) { if (isSign(tree, i)) check = true; } } else { for (int i = 0; i < function.Length; i++) { if (function[i] == '(') battery++; else if (function[i] == ')') battery--; } if (battery > 0) deleteBrackets(tree, "("); else if (battery < 0) deleteBrackets(tree, ")"); return; } } if (battery > 0 && !check) { deleteBrackets(tree, "("); deleteBrackets(tree, ")"); } }
// нахождение позиции тригонометрической функции private int findPosMathFunction(BinaryTree tree) { int posLog = tree.getData().IndexOf("log"); int posCos = tree.getData().IndexOf("cos"); int posSin = tree.getData().IndexOf("sin"); int posExp = tree.getData().IndexOf("exp"); if (posLog == 0) return posLog; else if (posCos == 0) return posCos; else if (posSin == 0) return posSin; else if (posExp == 0) return posExp; return -1; }
// регулярное выражение, определяющее является ли строка мат. знаком private bool isSign(BinaryTree tree, int pos) { string function = tree.getData(); if (function[pos] == '+' || function[pos] == '-' || function[pos] == '*' || function[pos] == '/' || function[pos] == '^') return true; return false; }
// основной метод разбора дерева private void parse(BinaryTree tree) { bool findCos = tree.getData().Contains("cos"); // ищем тригонометрические функции bool findSin = tree.getData().Contains("sin"); bool findLog = tree.getData().Contains("log"); bool findExp = tree.getData().Contains("exp"); int posOpenBracket = tree.getData().IndexOf("("); // ищем позиции ( и ) int posCloseBracket = tree.getData().IndexOf(")"); if ((findCos || findSin || findLog || findExp) && posOpenBracket != -1 && posCloseBracket != -1) { // это функция, содержащаю тригонометрические функции parseMathFunction(tree); } else if (posOpenBracket != -1 && posCloseBracket == -1) { // удаляем ( deleteBrackets(tree, "("); parse(tree); } else if (posOpenBracket == -1 && posCloseBracket != -1) { // удаляем ) deleteBrackets(tree, ")"); parse(tree); } else if (posOpenBracket != -1 && posCloseBracket != -1) { // это функци со скобками simplifyFunction(tree); // упрощаем его List<SignPriority> list = findAllSignes(tree); // находим все знаки SignPriority sp = sort(tree, list); // сортируем по знакам if (list.Count == 0 && sp == null) // если нет знаков, то во входной функции лишние скобки { deleteBrackets(tree, "("); // удаляем их deleteBrackets(tree, ")"); parse(tree); // продолжаем парсить входную строку } else { string sign = sp.getSign(); // получаем самый приоритетный знак int pos = sp.getPos(); // получаем его позицию во входной строке parseNext(tree, sign, pos); } } else if (posOpenBracket == -1 && posCloseBracket == -1) { // это функция без скобок if (CountMinus > 1) // если минусов больше, чем 1, то самый приоритетный знак - минус { findMathSign(tree, "-"); findMathSign(tree, "+"); findMathSign(tree, "*"); findMathSign(tree, "/"); findMathSign(tree, "^"); } else { findMathSign(tree, "+"); findMathSign(tree, "-"); findMathSign(tree, "*"); findMathSign(tree, "/"); findMathSign(tree, "^"); } } }
// нахождение всех ариф знаков во входной строке private List<SignPriority> findAllSignes(BinaryTree tree) { List<SignPriority> list = new List<SignPriority>(); String function = tree.getData(); int battery = 0; int someLength = function.Length - 2; for (int i = 0; i < someLength; i++) { if (function[i] == '(') // считаем кол-во скобочек battery++; else if (function[i] == ')') battery--; if (function[i] == '(' && i != 0) // скобка стоит не в начале, { if (isSign(tree, i - 1)) { if (battery == 0) // знак приоритетен list.Add(new SignPriority(i - 1, function.Substring(i - 1, 1), true)); else // знак не приоритетен list.Add(new SignPriority(i - 1, function.Substring(i - 1, 1), false)); } } else if (function[i] == ')' && function[i + 2] == '(' && isSign(tree, i + 1) && battery == 0) // добавление приоритетного знака между скобками { list.Add(new SignPriority(i + 1, function.Substring(i + 1, 1), true)); i += 2; battery++; } else if (function[i] == ')' && i != function.Length - 1 && isSign(tree, i + 1)) // добавление знака, стоящего после ) { if (battery == 0) list.Add(new SignPriority(i + 1, function.Substring(i + 1, 1), true)); else list.Add(new SignPriority(i + 1, function.Substring(i + 1, 1), false)); i++; } else if (isSign(tree, i) && battery == 0) list.Add(new SignPriority(i, function.Substring(i, 1), true)); } if (someLength > 0 && isSign(tree, someLength) && battery == 0) // для случая x+2 list.Add(new SignPriority(someLength, function.Substring(someLength, 1), true)); return list; }
// вычисление дерева private double calculateTree(BinaryTree tree, List<double> args) { double left = 0, right = 0, res = 0; if (tree.getData().Equals("+")) { left = calculate(tree.getLeft(), args); // считаем левую часть right = calculate(tree.getRight(), args); // считаем правую часть res = left + right; } else if (tree.getData().Equals("-")) { left = calculate(tree.getLeft(), args); // считаем левую часть right = calculate(tree.getRight(), args); // считаем правую часть res = left - right; } else if (tree.getData().Equals("*")) { left = calculate(tree.getLeft(), args); // считаем левую часть right = calculate(tree.getRight(), args); // считаем правую часть res = left * right; } else if (tree.getData().Equals("/")) { left = calculate(tree.getLeft(), args); // считаем левую часть right = calculate(tree.getRight(), args); // считаем правую часть res = left / right; } else if (tree.getData().Equals("^")) { left = calculate(tree.getLeft(), args); // считаем левую часть right = calculate(tree.getRight(), args); // считаем правую часть res = Math.Pow(left, right); } else if (tree.getData().Equals("cos")) { left = calculate(tree.getLeft(), args); // считаем левую часть res = Math.Cos(left); } else if (tree.getData().Equals("sin")) { left = calculate(tree.getLeft(), args); // считаем левую часть res = Math.Sin(left); } else if (tree.getData().Equals("exp")) { left = calculate(tree.getLeft(), args); // считаем левую часть res = Math.Exp(left); } else if (tree.getData().Equals("log")) { left = calculate(tree.getLeft(), args); // считаем левую часть res = Math.Log(left); } return res; }