Надо написать на основе алгоритма сортировочной станции калькулятор. Сам алгоритм довольно простой, однако мне бы хотелось реализовать его в ООП стиле, что усложняет задачу. Создал следующие классы:
public abstract class Operator implements AbstractToken{
protected String value;
protected int priority;
protected int countOperands;
public String getValueToken() {
return this.value;
}
protected double doСalculate(double[] operands) {
return 0;
}
public double calculate(double[] operands) {
return doСalculate(operands);
}
public int countOperands() {
return this.countOperands;
}
public int getPriority() {
return this.priority;
}
}
Классы Sub, Div, Mult, Pow реализованы аналогично Add
public class Add extends Operator {
Add() {
this.value = "+";
this.priority = 0;
this.countOperands = 2;
}
@Override
protected double doСalculate(double[] operands) {
return operands[0] + operands[1];
}
}
Класс Token
public class Token implements AbstractToken {
String value;
Token(String value) {
this.value = value;
}
public boolean isCloseBracket(){
return this.value == ")";
}
public boolean isOpenBracket(){
return this.value == "(";
}
}
Идея заключалась в том, чтобы поместить с помощью интерфейса AbstractToken в массив объекты Operator, Token. А дальше работать с массивом, реализуя алгоритм. Концептуально я представлял себе так:
private ArrayList<AbstractToken> toPostfix(ArrayList<AbstractToken> tokens) {
ArrayList<AbstractToken> infexExpression = new ArraList<AbstractToken>()
Stack<AbstractToken> stack = new Stack<AbstractToken>()
for (AbstractToken token : tokens) {
if(token instanceof Operator){
//...
}
else {
//...
}
}
}
Однако я столкнулся с тем, что не могу обращаться к методам классов Operator и Token, что вполне очевидно, когда понимаешь для чего необходимо использовать интерфейсы. Подумав и посмотрев на этот код, я понял, что это полное безобразие и не понимаю ооп. Вопросы:
Интересный вопрос и самое смешное, что я действительно не смог найти ООП реализации (только процедурный код), посему набросал простенькое решение.
public interface Token {
//pattern 'Factory method '
public static Token of(String token) {
try {
switch (token) {
case "+": return new Add();
case "*": return new Mult();
case "-": return new Sub();
case "/": return new Div();
case "^": return new Pow();
case "(": return new BracketOpen();
case ")": return new BracketClose();
}
return new TokenNumber(Double.valueOf(token));
} catch (NumberFormatException | NullPointerException e) {
throw new UnsupportedOperationException("Not supported for token " + token);
}
}
public int getPriority();
public Double execute(CalculationPool calculationPool);
public void addToken(CalculationPool calculationPool);
}
public abstract class TokenImpl implements Token{
private final int priority;
public TokenImpl(int priority) {
this.priority = priority;
}
@Override
public int getPriority() {
return priority;
}
}
public class TokenNumber extends TokenImpl{
private final Double value;
public TokenNumber(Double value) {
super(-1);
this.value = value;
}
@Override
public String toString() {
return String.valueOf(value);
}
@Override
public Double execute(CalculationPool calculationPool) {
return value;
}
@Override
public void addToken(CalculationPool calculationPool) {
calculationPool.addToQueue(this);
}
}
import java.util.function.BinaryOperator;
public abstract class TokenFunction extends TokenImpl {
public TokenFunction(int priority) {
super(priority);
}
@Override
public void addToken(CalculationPool calculationPool) {
calculationPool.toStack(this);
}
//pattern 'Template method '
@Override
public Double execute(CalculationPool calculationPool) {
return getOperation().apply(calculationPool.pollFromNumber(), calculationPool.pollFromNumber());
}
protected abstract BinaryOperator<Double> getOperation();
}
public abstract class TokenBracket extends TokenImpl{
public TokenBracket(int priority) {
super(priority);
}
@Override
public Double execute(CalculationPool calculationPool) {
throw new UnsupportedOperationException("Unsupported operation for this token : " + this);
}
}
public class BracketClose extends TokenBracket{
public BracketClose() {
super(1);
}
@Override
public void addToken(CalculationPool calculationPool) {
calculationPool.toStack(this);
calculationPool.pollFromStack();
calculationPool.pollFromStack();
}
@Override
public String toString() {
return ")";
}
}
public class BracketOpen extends TokenBracket{
public BracketOpen() {
super(0);
}
@Override
public void addToken(CalculationPool calculationPool) {
calculationPool.addToStack(this);
}
@Override
public String toString() {
return "(";
}
}
import java.util.function.BinaryOperator;
public class Add extends TokenFunction {
public Add() {
super(2);
}
@Override
protected BinaryOperator<Double> getOperation() {
return (x,y)->y+x;
}
@Override
public String toString() {
return "+";
}
}
import java.util.function.BinaryOperator;
public class Div extends TokenFunction{
public Div() {
super(3);
}
@Override
protected BinaryOperator<Double> getOperation() {
return (x,y)->y/x;
}
@Override
public String toString() {
return "/";
}
}
import java.util.function.BinaryOperator;
public class Mult extends TokenFunction {
public Mult() {
super(3);
}
@Override
protected BinaryOperator<Double> getOperation() {
return (x,y)->y*x;
}
@Override
public String toString() {
return "*";
}
}
import java.util.function.BinaryOperator;
public class Pow extends TokenFunction {
public Pow() {
super(4);
}
@Override
protected BinaryOperator<Double> getOperation() {
return (x,y)->Math.pow(y,x);
}
@Override
public String toString() {
return "^";
}
}
import java.util.function.BinaryOperator;
public class Sub extends TokenFunction{
public Sub() {
super(2);
}
@Override
protected BinaryOperator<Double> getOperation() {
return (x,y)->y-x;
}
@Override
public String toString() {
return "-";
}
}
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
public class CalculationPool {
private final Deque<Token> OUTPUT_QUEUE = new ArrayDeque<>();
private final Deque<Token> STACK = new ArrayDeque<>();
private final Deque<Double> NUMBERS = new ArrayDeque<>();
public CalculationPool() {}
public CalculationPool(String ... values) {
addToken(values);
}
public Token pollFromStack (){
return STACK.pollFirst();
}
public Double pollFromNumber (){
return NUMBERS.pollLast();
}
public void addToQueue (Token token){
OUTPUT_QUEUE.add(token);
}
public void addToStack (Token token){
STACK.addFirst(token);
}
public void toStack(Token token) {
final Iterator<Token> iterator = STACK.iterator();
while (iterator.hasNext()) {
final Token nextToken = iterator.next();
if (token.getPriority() > nextToken.getPriority()) break;
addToQueue(nextToken);
iterator.remove();
}
addToStack(token);
}
public CalculationPool addToken(String value){
Token.of(value).addToken(this);
return this;
}
public final CalculationPool addToken(String ... values){
for (String value : values) addToken(value);
return this;
}
public Double calculate() {
OUTPUT_QUEUE.addAll(STACK);
OUTPUT_QUEUE.forEach(token->NUMBERS.add(token.execute(this)));
return NUMBERS.getFirst();
}
}
public class Main {
public static void main(String[] args) {
//можно инициализировать так
final Double result1 = new CalculationPool()
.addToken("7").addToken("+")
.addToken("5").addToken("*").addToken("2")
.calculate();
//а можно так
final Double result2 = new CalculationPool()
.addToken("3", "+", "4", "*", "2", "/", "(", "1", "-", "5", ")", "^", "2")
.calculate();
//или так
final Double result3 = new CalculationPool("(", "6", "+", "10", "-", "4", ")", "/", "(", "1", "+", "1", "*", "2", ")", "+", "1")
.calculate();
System.out.println(result1);
System.out.println(result2);
System.out.println(result3);
}
}
Парсер математически выражений на вашей совести. Если есть вопросы - задавайте. Удачи!
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Как лучше организовать заведомо долгий отложенный поток?
Решил порешать задачи которые готовит ЯндексНаткнулся на первые трудности в виде задачи про дубликаты:
Использую библиотеку materializecssНа главной странице проекта вывожу раскрывающиеся карточки, в три колонки