您的位置:首页 > 编程语言 > Java开发

计算器算法实现java

2018-03-06 15:16 471 查看
测试类:

package com.fly.design.calculate;

import org.junit.Test;

import static org.junit.Assert.*;

/**
* @author weijun.zou
* Create on 2018/3/6
*/
public class ExpressionTest {
@Test
public void calculate() throws Exception {
assertEquals(-6, Expression.calculate("((4+5)-(3*4))*2").intValue());
assertEquals(0, Expression.calculate("5%5").intValue());
assertEquals(-1000, Expression.calculate("-(3+3+4)^(3*(2-1))").intValue());
}

}


算法:

package com.fly.design.calculate;

import com.fly.design.calculate.utils.ArrayStack;
import com.fly.design.calculate.utils.Stack;

import java.util.Objects;

/**
* @author weijun.zou
* Create on 2018/3/6
*/
public class Expression {

private static final char LEFT_BRACKET = '(';
private static final char RIGHT_BRACKET = ')';
private static final char MINUS = '-';
private static final char SPACE = ' ';

/**
* 将一个表达式计算出结果
*
* @param expressString 表达式
* @return 数字
*/
public static Number calculate(String expressString) {
Objects.requireNonNull(expressString);
int capacity = expressString.length() / 4;
Stack<Integer> leftBracketStack = new ArrayStack<>(capacity);
int index = 0;
String bracketString = expressString;
for (char symbol : expressString.toCharArray()) {
if (symbol == LEFT_BRACKET) {
leftBracketStack.push(index);
index++;
} else if (symbol == RIGHT_BRACKET) {
/*
* 计算括号里的值
*/
int rightBracket = index;
int leftBracket = leftBracketStack.pop();
String simpleExpress = bracketString.substring(leftBracket + 1, rightBracket);
Number number = calculate(new NumberElement(simpleExpress));
String value = number.toString();
/*
* 简化括号表达式
*/
bracketString = bracketString.substring(0, leftBracket)
+ value
+ bracketString.substring(rightBracket + 1);
index = leftBracket + value.length();
} else {
index++;
}
}
return calculate(new NumberElement(bracketString));
}

private static Number calculate(NumberElement root) {
Objects.requireNonNull(root);
/*
* 从左至右,根据操作符的优先级计算
*/
Stack<NumberElement> stack = new ArrayStack<>();
stack.push(root);
NumberElement nextElement = root.nextElement;

while (Objects.nonNull(nextElement)) {
NumberElement numberElement = stack.pop();
//判断当前numberElement的操作符是否可以优先计算
if (Operator.priority(numberElement.preOperator, nextElement.preOperator)) {
//获取element的操作符左边的数
NumberElement preNumber = stack.pop();
//将合并后的新的操作数存入栈中
stack.push(merge(preNumber, numberElement));
} else {
stack.push(numberElement);
stack.push(nextElement);
nextElement = nextElement.nextElement;
}
}
NumberElement result = stack.pop();
while (!stack.isEmpty()) {
NumberElement preNumber = stack.pop();
result = merge(preNumber, result);
}
return result.number;
}

private static NumberElement merge(NumberElement preNumber, NumberElement numberElement) {
Objects.requireNonNull(preNumber);
Objects.requireNonNull(numberElement);
Number number = numberElement.preOperator.calculate(preNumber.number, numberElement.number);
return new NumberElement(preNumber.preOperator, number.doubleValue(), numberElement.nextElement);
}

private static class NumberElement {
//前置操作符
private Operator preOperator;
//数字
private double number;
//下一个操作数
private NumberElement nextElement;

NumberElement(Operator preOperator, double number, NumberElement nextElement) {
this.preOperator = preOperator;
this.number = number;
this.nextElement = nextElement;
}

NumberElement() {

}

NumberElement(String string) {
Objects.requireNonNull(string);
char[] chars = string.trim().toCharArray();
int index = 0;
NumberElement tail = new NumberElement();
tail.nextElement = this;
while (index < chars.length) {
if (chars[index] == SPACE) {
index++;
continue;
}
Operator preOperator = null;
//获取数字之前的操作符,但不包括负号
if (index > 0 && Operator.isOperator(String.valueOf(chars[index]))) {
preOperator = Operator.get(String.valueOf(chars[index]));
index++;
}
//获取数字
int cursor;
for (cursor = index; cursor < chars.length; cursor++) {
//负号
if (cursor == index && chars[cursor] == MINUS) continue;
//操作符
if (Operator.isOperator(String.valueOf(chars[cursor]))) {
break;
}
}
double number = Double.valueOf(string.substring(index, cursor));
tail = tail.nextElement;
tail.preOperator = preOperator;
tail.number = number;
tail.nextElement = new NumberElement();
index = cursor;
}
tail.nextElement = null;
}
}
}


package com.fly.design.calculate;

import java.util.Arrays;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiFunction;

import static java.util.stream.Collectors.toMap;

/**
* @author weijun.zou
* Create on 2018/2/11
* 运算符
*/
public enum Operator {

ADDITION("+", 0, (a, b) -> a.doubleValue() + b.doubleValue()),
SUBTRACTION("-", 0, (a, b) -> a.doubleValue() - b.doubleValue()),
MULTIPLICATION("*", 10, (a, b) -> a.doubleValue() * b.doubleValue()),
DIVISION("/", 10, (a, b) -> a.doubleValue() / b.doubleValue()),
MODULUS("%", 10, (a, b) -> a.doubleValue() % b.doubleValue()),
POWER("^", 100, (a, b) -> Math.pow(a.doubleValue(), b.doubleValue())),

DEFAULT(null, Integer.MAX_VALUE, true, (a, b) -> {
throw new RuntimeException("该运算符不存在");
});

private static Map<String, Operator> operatorMap =
Arrays.stream(Operator.values())
.collect(toMap(Operator::getSymbol, operator -> operator));

/**
* null false
* notnull null true
* notnull notnull 比较priority、相等再看isLeftOrder
*/
public static boolean priority(Operator operator, Operator contrast) {
//operator为null一律为false
if (Objects.isNull(operator)) {
return false;
}
/* true:
* 后者为null
* 前者priority大于后者
* 相等且从左到右的顺序
*/
return Objects.isNull(contrast)
|| operator.priority > contrast.priority
|| (operator.priority == contrast.priority && operator.isLeftOrder());
}

public static boolean isOperator(String operator) {
return operatorMap.containsKey(operator);
}

public static Operator get(String symbol) {
return operatorMap.getOrDefault(symbol, DEFAULT);
}

private BiFunction<Number, Number, Number> function;
private String symbol;
private int priority;
private boolean isLeftOrder;

Operator(String symbol, int priority, BiFunction<Number, Number, Number> function) {
this.symbol = symbol;
this.priority = priority;
isLeftOrder = true;
this.function = function;
}

Operator(String symbol, int priority, boolean isLeftOrder, BiFunction<Number, Number, Number> function) {
this.symbol = symbol;
this.priority = priority;
this.isLeftOrder = isLeftOrder;
this.function = function;
}

public Number calculate(Number a, Number b) {
return function.apply(a, b);
}

public String getSymbol() {
return symbol;
}

@Override
public String toString() {
return symbol;
}

public boolean isLeftOrder() {
return isLeftOrder;
}
}


package com.fly.design.calculate.utils;

import java.util.List;

/**
* @author weijun.zou
* Create on 2018/2/17
*/
public interface Stack<E> {
E push(E item);
E pop();
boolean isEmpty();
List<E> toList();
}


package com.fly.design.calculate.utils;

import java.util.ArrayList;
import java.util.List;

/**
* @author weijun.zou
* Create on 2018/2/17
*/
public class ArrayStack<E> implements Stack<E> {

private List<E> list ;

public ArrayStack() {
list = new ArrayList<>();
}

public ArrayStack(int capacity){
list = new ArrayList<>(capacity);
}

@Override
public E push(E item) {
boolean success = list.add(item);
if (success) {
return item;
} else {
throw new RuntimeException("push item failed");
}
}

@Override
public E pop() {
if (list.isEmpty()) {
throw new RuntimeException("pop failed, none item");
} else {
return list.remove(list.size() - 1);
}
}

@Override
public List<E> toList() {
return new ArrayList<>(list);
}

@Override
public boolean isEmpty() {
return list.isEmpty();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: