301
社区成员
发帖
与我相关
我的任务
分享
本次作业主要内容可以简单分为三部分:预处理, 解析表达式,计算化简
while (input.contains("++") || input.contains("--")
|| input.contains("+-") || input.contains("-+")) {
input = input.replaceAll("\\+\\+", "+");
input = input.replaceAll("\\+-", "-");
input = input.replaceAll("-\\+", "-");
input = input.replaceAll("--", "+");
}
使用while实现递归查找,保证所有的重复符号都被替换。实际上本人由于性格叛逆,一开始没有使用预处理方法,而是选择在Parser类解析过程中使用控制流来处理符号,这样导致方法冗长并且由于没有注意形式化表达,忽略了+-+1的情况。(表达式,项,因子各带一个符号)
Lexer和Parser其中Lexer负责解析输入的字符串并返回输出,Parser根据返回的输出进行解析。举个例子:x*(x+3*x^3)+x^2+1(1)整个式子就是一个 表达式 ,因此直接进入ParseExpr方法,ParseExpr中使用+``-进行分割,第一个项直接调用ParseTerm,随后每读到一个符号之后就再调用一次ParseTerm进入对 项 的分析。在进入 项 的分析之前,我们很容易注意到, 项 之前有两种符号而因子只有一个。这就意味着 项 在组成***的时候复杂度提高了。为了避免这种复杂度,我们将符号作为 项 的一个属性,这样的话就可以简单把 项 相加来组成 表达式 了。在本例中直接进入第一项``x(x+3*x^3)``的分析。 public Expr parseExpr() {
Expr expr = new Expr();
int signf = 1;
//get the first terms
if (lexer.now().equals("-")) {
lexer.next();
signf = -1; // the first signal is minus
} else if (lexer.now().equals("+")) {
lexer.next();
}
expr.addTerm(parseTerm(signf));
//get the terms left
while (lexer.now().equals("-") || lexer.now().equals("+")) {
int sign = 1;
if (lexer.now().equals("-")) {
lexer.next();
sign = -1; // the first signal is minus
} else {
lexer.next();
}
expr.addTerm(parseTerm(sign));
}
return expr;
}
(2)进入 项 的分析后,我们不难想到 项 的 因子 之间是通过乘号分割的,于是同样的第一个 因子 直接调用ParseFactor,随后每读到一个符号之后再调用ParseFactor进入对 因子 的分析。
public Term parseTerm(int sign) {
Term term = new Term(sign);
//get the first factor
term.addFactor(parseFactor());
//get the left factors
int signmodi = sign;
while (lexer.now().equals("*")) {
lexer.next();
if (lexer.now().equals("-")) {
signmodi = signmodi * -1;
lexer.next();
} else if (lexer.now().equals("+")) {
lexer.next();
}
term.addFactor(parseFactor());
}
term.setSign(signmodi);
return term;
}
(3)在对于 因子 的分析中,直接调用ParseFactor 方法。我是将Factor 作为一个父类,子类重写相应的方法,在调用的时候可以直接进入子类对应重写的方法。这里比较难以理解的就是对于 表达式因子 的分析,类似一个递归调用,再次调用分析括号中的 表达式 即可。
Poly 类和 Mono 类。其中 Mono 作为最小计算单元: public class Mono { private BigInteger coe;
private int exp;
} 通过对已经解析完毕的表达式中依次调用toPoly()方法
// Expr
public Poly toPoly() {
Poly poly = new Poly();
for (Term it : terms) {
Poly temp = poly.addPoly(it.toPoly());
poly = temp;
}
return poly;
}
//Term
public Poly toPoly() {
Poly poly = new Poly();
for (Factor it : factors) {
Poly temp = new Poly();
if (it instanceof Powerfactor) {
Powerfactor xfactor = (Powerfactor) it;
temp = poly.mulPoly(xfactor.toPoly());
} else if (it instanceof Exprfactor) {
Exprfactor efactor = (Exprfactor) it;
temp = poly.mulPoly(efactor.toPoly());
} else if (it instanceof Numfactor) {
Numfactor cfactor = (Numfactor) it;
temp = poly.mulPoly(cfactor.toPoly());
} // 这里直接调用就可以,不需要进行判断,在第一次作业中还不知道
poly = temp;
}
if (sign == -1) {
poly.negate();
}
return poly;
}
//Factor
//...
在成功解析后,再对调用 Poly 的 toString 方法即可。
| Method | CogC | ev(G) | iv(G) | v(G) |
|---|---|---|---|---|
| Expr.Expr() | 0 | 1 | 1 | 1 |
| Expr.addTerm(Term) | 0 | 1 | 1 | 1 |
| Expr.toPoly() | 1 | 1 | 2 | 2 |
| "Exprfactor.Exprfactor(int, Expr)" | 0 | 1 | 1 | 1 |
| Exprfactor.toPoly() | 0 | 1 | 1 | 1 |
| Factor.Factor(int) | 0 | 1 | 1 | 1 |
| Factor.getExp() | 0 | 1 | 1 | 1 |
| Lexer.Lexer(String) | 0 | 1 | 1 | 1 |
| Lexer.getNumber() | 2 | 1 | 3 | 3 |
| Lexer.next() | 4 | 2 | 3 | 4 |
| Lexer.now() | 0 | 1 | 1 | 1 |
| MainClass.main(String[]) | 2 | 1 | 2 | 2 |
| "Mono.Mono(BigInteger, int)" | 0 | 1 | 1 | 1 |
| Mono.getCoe() | 0 | 1 | 1 | 1 |
| Mono.getExp() | 0 | 1 | 1 | 1 |
| Mono.setCoe(BigInteger) | 0 | 1 | 1 | 1 |
| Mono.toString() | 8 | 6 | 6 | 6 |
| "Numfactor.Numfactor(int, BigInteger)" | 0 | 1 | 1 | 1 |
| Numfactor.toPoly() | 0 | 1 | 1 | 1 |
| Parser.Parser(Lexer) | 0 | 1 | 1 | 1 |
| Parser.parseExpr() | 7 | 1 | 6 | 6 |
| Parser.parseFactor() | 13 | 3 | 7 | 7 |
| Parser.parseTerm(int) | 4 | 1 | 4 | 4 |
| Poly.Poly() | 0 | 1 | 1 | 1 |
| "Poly.addMono(int, Mono)" | 2 | 1 | 2 | 2 |
| Poly.addPoly(Poly) | 8 | 1 | 6 | 6 |
| Poly.mulPoly(Poly) | 12 | 2 | 6 | 6 |
| Poly.negate() | 3 | 1 | 3 | 3 |
| Poly.powPoly(int) | 3 | 3 | 2 | 3 |
| Poly.toStirng() | 27 | 3 | 10 | 11 |
| Powerfactor.Powerfactor(int) | 0 | 1 | 1 | 1 |
| Powerfactor.toPoly() | 0 | 1 | 1 | 1 |
| Processor.delBlank(String) | 4 | 1 | 3 | 4 |
| Processor.processSymbol(String) | 2 | 1 | 5 | 5 |
| Term.Term(int) | 0 | 1 | 1 | 1 |
| Term.addFactor(Factor) | 0 | 1 | 1 | 1 |
| Term.setSign(int) | 0 | 1 | 1 | 1 |
| Term.toPoly() | 6 | 1 | 6 | 6 |

第二次作业增加了exp和自定义函数。
FuncProcess 和 Funcfactor对自定义函数的处理,简单来说就是将自定义函数转换为普通因子。我采用的方法是字符串替换。 int num = Integer.parseInt(scanner.nextLine());
for (int i = 0; i < num; i++) {
String inputfunc = Processor.delBlank(scanner.nextLine());
inputfunc = inputfunc.replace("exp", "e");
Funcprocess.addFunc(inputfunc);
}
// FuncProcess
private static HashMap<String, String> funcMap = new HashMap<>(); // 存储自定义函数表达式
private static HashMap<String, ArrayList<String>> paraMap = new HashMap<>(); // 存储形参和实参的对应
public static void addFunc(String input) {
String name = String.valueOf(input.charAt(0));
funcMap.put(name, input.split("=")[1]);
int startindex = input.indexOf('(');
int endindex = input.indexOf(')');
String paraget = input.substring(startindex + 1, endindex);
ArrayList<String> paralist = new ArrayList<>(Arrays.asList(paraget.split(",")));
paraMap.put(name, paralist);
}
(2)解析函数因子 //Funcfactor
private String newFunc; //将函数实参带入形参位置后的结果(字符串形式)
private Expr expr; //将newFunc解析成表达式后的结果
public Funcfactor(String name, ArrayList<Factor> actualparas) {
super(BigInteger.ONE);
this.newFunc = Funcprocess.callFunc(name, actualparas);
this.expr = toExpr();
}
public static String callFunc(String name, ArrayList<Factor> actualParas) {
String func = funcMap.get(name);
ArrayList<String> paraList = paraMap.get(name);
Map<String, String> replacementMap = new LinkedHashMap<>();
for (int i = 0; i < paraList.size(); i++) {
if (actualParas.get(i).toPoly().toString().isEmpty()) {
replacementMap.put(paraList.get(i), "0");
} else {
replacementMap.put(paraList.get(i), actualParas.get(i).toPoly().toString());
}
}
String[] orderedParams = {"x", "y", "z"};
for (String param : orderedParams) {
if (replacementMap.containsKey(param)) {
func = func.replace(param, "(" + replacementMap.get(param) + ")");
}
}
func = Processor.processSymbol(func);
return func;
}
这里要注意,字符串替换的时候会产生一些问题:
f(y,x) = x + 2的情况,只按照参数出现的顺序进行调用就会出问题,所以最好按照xyz的顺序替换主要的难点出在之后的计算,由于新增了exp,导致多项式相加时能否合并的判断变得复杂了很多。我在第二次作业中新增了 Pair类进行判断,同时重写了Poly的.equals()方法。
public class Pair {
private BigInteger varExp;
private BigInteger expExp;
private Poly expPoly;
private Poly wholeExpPoly;
public Pair(BigInteger varExp, BigInteger expExp, Poly expPoly) {
this.varExp = varExp;
this.expPoly = expPoly;
this.expExp = expExp;
if (expPoly != null) {
if (!expPoly.isPolyEmpty()) {
this.wholeExpPoly = expPoly.mulPoly(Poly.getConstPoly(expExp));
} else {
this.wholeExpPoly = expPoly.getEmptyPoly();
}
} else {
System.out.println("expPoly is null");
}
}
在对Pair的判等中又涉及到对Poly的判等
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Poly poly = (Poly) o;
if (monoMap.size() != poly.monoMap.size()) {
return false;
}
for (Pair key : monoMap.keySet()) {
if (!poly.monoMap.containsKey(key)) {
return false;
}
ArrayList<Mono> thisList = monoMap.get(key);
ArrayList<Mono> thatList = poly.monoMap.get(key);
if (thisList.size() != thatList.size() ||
!thisList.containsAll(thatList) || !thatList.containsAll(thisList)) {
return false;
}
}
return true;
}
这里对Poly的判等还可以通过调用toString方法比较字符串来实现,但这样反复地递归调用很可能会TLE,因此本人采用了分析内部结构的办法。这个方法虽然大大降低了时间复杂度,但由于我的一些处理不到位,在后续带来了一些问题,虽然修改是在第三次作业的重构中完成的,但是由于是第二次作业的内容,我就把它放到这里来讲。
这个问题就是:对0的处理
Poly为0的时候,它应该是什么样呢?是空的,还是能够有Mono但是Momo全都为0呢?
在我对Poly的判等中,采用了返回size是否相等的办法,这就意味着我只能采用第一种办法。因为如果Poly1中有一个Mono为1,而Poly2中有一个为1的Mono和一个为0的Mono,我的程序会判断他们不相等。这就造成了合并同类项困难的问题。
于是在后续的程序中,我统一将空的Poly视为0。同时在加乘中对0进行特判来简化逻辑。并为了防止大家提到的深浅拷贝问题,在加减中统一进行深拷贝,返回新的Poly。
此处Mono Poly Pair三者形成了类似递归的拷贝,我们将0设为终点。
拷贝参考代码如下:
// pair
public static Pair deepCopyPair(Pair another) {
Poly expPoly = another.expPoly.isPolyZero() ?
Poly.getZeroPoly() : Poly.deepCopyPoly(another.expPoly);
return new Pair(another.varExp, another.expExp, expPoly);
}
// Mono
public static Mono deepCopyMono(Mono another) {
Poly expPoly = another.expPoly.isPolyZero() ?
Poly.getZeroPoly() : Poly.deepCopyPoly(another.expPoly);
return new Mono(another.coe, another.varExp, another.expExp, expPoly);
}
// Poly
public static Poly deepCopyPoly(Poly another) {
Poly clonePoly = new Poly();
for (Map.Entry<Pair, ArrayList<Mono>> entry : another.monoMap.entrySet()) {
Pair pair = Pair.deepCopyPair(entry.getKey());
ArrayList<Mono> monoList = new ArrayList<>();
for (Mono mono : entry.getValue()) {
monoList.add(Mono.deepCopyMono(mono));
}
clonePoly.monoMap.put(pair, monoList);
}
return clonePoly;
}
具体加和乘的计算这里不再赘述。
关于重构的体验,我实际上是在第三次作业完成通过中测后才进行的重构。当时本来想着,中测都过了,也已经是最后一次迭代,或许不再有重构的必要了。但是看着运行时一大堆000000和最后没有被完全合并的式子,还是不甚满意,进行了上述重构。
实际上,有了完整正确思路的重构并不像想象中那么复杂,我只花了一个下午就完成了。因此,面对不完美的代码,重构是势在必行的。关键是在重构之前必须有亟待解决的问题和完整的思路,否则很可能在重构的过程中就不知道自己在干什么了。
| Method | CogC | ev(G) | iv(G) | v(G) |
|---|---|---|---|---|
| Expfactor.Expfactor(BigInteger, Expr) | 0 | 1 | 1 | 1 |
| Expfactor.toPoly() | 0 | 1 | 1 | 1 |
| Expr.Expr() | 0 | 1 | 1 | 1 |
| Expr.addTerm(Term) | 0 | 1 | 1 | 1 |
| Expr.toPoly() | 1 | 1 | 2 | 2 |
| Exprfactor.Exprfactor(BigInteger, Expr) | 0 | 1 | 1 | 1 |
| Exprfactor.toPoly() | 0 | 1 | 1 | 1 |
| Factor.Factor(BigInteger) | 0 | 1 | 1 | 1 |
| Factor.getExp() | 0 | 1 | 1 | 1 |
| Factor.toPoly() | 8 | 5 | 5 | 5 |
| Funcfactor.Funcfactor(String, ArrayList) | 0 | 1 | 1 | 1 |
| Funcfactor.toExpr() | 0 | 1 | 1 | 1 |
| Funcfactor.toPoly() | 0 | 1 | 1 | 1 |
| Funcprocess.addFunc(String) | 0 | 1 | 1 | 1 |
| Funcprocess.callFunc(String, ArrayList) | 7 | 1 | 5 | 5 |
| Lexer.Lexer(String) | 0 | 1 | 1 | 1 |
| Lexer.getNumber() | 2 | 1 | 3 | 3 |
| Lexer.next() | 7 | 2 | 6 | 7 |
| Lexer.now() | 0 | 1 | 1 | 1 |
| MainClass.main(String[]) | 6 | 1 | 4 | 4 |
| Mono.Mono(BigInteger, BigInteger, BigInteger, Poly) | 5 | 1 | 3 | 3 |
| Mono.addCoe(BigInteger) | 0 | 1 | 1 | 1 |
| Mono.equals(Object) | 4 | 3 | 4 | 6 |
| Mono.findClosingBracket(String, int) | 7 | 5 | 3 | 5 |
| Mono.getCoe() | 0 | 1 | 1 | 1 |
| Mono.getExpExp() | 0 | 1 | 1 | 1 |
| Mono.getExpPoly() | 0 | 1 | 1 | 1 |
| Mono.getVarExp() | 0 | 1 | 1 | 1 |
| Mono.getWholeExpPoly() | 0 | 1 | 1 | 1 |
| Mono.hashCode() | 0 | 1 | 1 | 1 |
| Mono.isFactor(String) | 9 | 5 | 7 | 9 |
| Mono.mulMono(Mono, Mono) | 3 | 2 | 2 | 3 |
| Mono.setCoe(BigInteger) | 0 | 1 | 1 | 1 |
| Mono.toString() | 22 | 7 | 11 | 15 |
| Numfactor.Numfactor(BigInteger, BigInteger) | 0 | 1 | 1 | 1 |
| Numfactor.toPoly() | 0 | 1 | 1 | 1 |
| Pair.Pair(BigInteger, BigInteger, Poly) | 5 | 1 | 3 | 3 |
| Pair.equals(Object) | 4 | 3 | 3 | 5 |
| Pair.getExpExp() | 0 | 1 | 1 | 1 |
| Pair.getExpPoly() | 0 | 1 | 1 | 1 |
| Pair.getVarExp() | 0 | 1 | 1 | 1 |
| Pair.getWholeExpPoly() | 0 | 1 | 1 | 1 |
| Pair.hashCode() | 0 | 1 | 1 | 1 |
| Parser.Parser(Lexer) | 0 | 1 | 1 | 1 |
| Parser.isNum(String) | 3 | 3 | 2 | 3 |
| Parser.parseExpr() | 7 | 1 | 6 | 6 |
| Parser.parseExprFactor() | 3 | 1 | 3 | 3 |
| Parser.parseFactor() | 21 | 6 | 12 | 12 |
| Parser.parseFuncFactor() | 1 | 1 | 2 | 2 |
| Parser.parseTerm(int) | 4 | 1 | 4 | 4 |
| Poly.Poly() | 0 | 1 | 1 | 1 |
| Poly.addAllMono() | 10 | 3 | 6 | 7 |
| Poly.addMono(Pair, Mono) | 2 | 1 | 2 | 2 |
| Poly.addPoly(Poly) | 12 | 1 | 10 | 10 |
| Poly.equals(Object) | 10 | 7 | 5 | 10 |
| Poly.getConstPoly(BigInteger) | 0 | 1 | 1 | 1 |
| Poly.getEmptyPoly() | 0 | 1 | 1 | 1 |
| Poly.hashCode() | 0 | 1 | 1 | 1 |
| Poly.isPolyEmpty() | 0 | 1 | 1 | 1 |
| Poly.mulPoly(Poly) | 12 | 2 | 6 | 6 |
| Poly.negate() | 3 | 1 | 3 | 3 |
| Poly.polyString(ArrayList<Mono>) | 26 | 3 | 9 | 10 |
| Poly.powPoly(BigInteger) | 3 | 3 | 2 | 3 |
| Poly.toString() | 1 | 1 | 2 | 2 |
| Powerfactor.Powerfactor(BigInteger) | 0 | 1 | 1 | 1 |
| Powerfactor.toPoly() | 0 | 1 | 1 | 1 |
| Processor.delBlank(String) | 4 | 1 | 3 | 4 |
| Processor.processSymbol(String) | 2 | 1 | 5 | 5 |
| Term.Term(int) | 0 | 1 | 1 | 1 |
| Term.addFactor(Factor) | 0 | 1 | 1 | 1 |
| Term.setSign(int) | 0 | 1 | 1 | 1 |
| Term.toPoly() | 8 | 1 | 8 | 8 |
第三次作业中,方法复杂度高的方法基本上都是toString方法,由于需要优化和括号处理而进行的许多特判产生的高复杂度,本人认为并不容易降低,所幸也没产生bug,那也就无所谓了。

第三次作业比较简单,求导功能的实现只需遵循求导法则对每个解析存储类写一个求导方法即可。
// Expr
public Poly todxPoly() {
Poly poly = new Poly();
for (Term it : terms) {
Poly temp = poly.addPoly(it.todxPoly());
poly = temp;
}
return poly;
}
//Term
public Poly todxPoly() {
Poly poly = new Poly();
for (int i = 0; i < factors.size(); i++) {
Poly temp = Poly.getConstPoly(BigInteger.ONE);
for (int j = 0; j < factors.size(); j++) {
if (i != j) {
temp = temp.mulPoly(factors.get(j).toPoly());
} else {
temp = temp.mulPoly(factors.get(j).todxPoly());
}
}
poly = poly.addPoly(temp);
}
if (sign == -1) {
poly.negate();
}
return poly;
}
//Defactor
public Poly todxPoly() {
Poly poly1 = expr.todxPoly().powPoly(super.getExp());
String exprString = poly1.toString();
Expr expr1 = new Expr();
if (exprString.isEmpty()) {
expr1 = toExpr("0");
} else {
expr1 = toExpr(exprString);
}
Poly poly = expr1.todxPoly().powPoly(super.getExp());
return poly;
}
| Method | CogC | ev(G) | iv(G) | v(G) |
|---|---|---|---|---|
| Defactor.Defactor(BigInteger, Expr) | 0 | 1 | 1 | 1 |
| Defactor.toExpr(String) | 0 | 1 | 1 | 1 |
| Defactor.toPoly() | 0 | 1 | 1 | 1 |
| Defactor.todxPoly() | 2 | 1 | 2 | 2 |
| Expfactor.Expfactor(BigInteger, Expr) | 0 | 1 | 1 | 1 |
| Expfactor.toPoly() | 0 | 1 | 1 | 1 |
| Expfactor.todxPoly() | 1 | 2 | 2 | 2 |
| Expr.Expr() | 0 | 1 | 1 | 1 |
| Expr.addTerm(Term) | 0 | 1 | 1 | 1 |
| Expr.toPoly() | 1 | 1 | 2 | 2 |
| Expr.todxPoly() | 1 | 1 | 2 | 2 |
| Exprfactor.Exprfactor(BigInteger, Expr) | 0 | 1 | 1 | 1 |
| Exprfactor.toPoly() | 0 | 1 | 1 | 1 |
| Exprfactor.todxPoly() | 0 | 1 | 1 | 1 |
| Factor.Factor(BigInteger) | 0 | 1 | 1 | 1 |
| Factor.getExp() | 0 | 1 | 1 | 1 |
| Factor.toPoly() | 0 | 1 | 1 | 1 |
| Factor.todxPoly() | 0 | 1 | 1 | 1 |
| Funcfactor.Funcfactor(String, ArrayList) | 0 | 1 | 1 | 1 |
| Funcfactor.toExpr() | 0 | 1 | 1 | 1 |
| Funcfactor.toPoly() | 0 | 1 | 1 | 1 |
| Funcfactor.todxPoly() | 0 | 1 | 1 | 1 |
| Funcprocess.addFunc(String) | 0 | 1 | 1 | 1 |
| Funcprocess.callFunc(String, ArrayList<Factor>) | 7 | 1 | 5 | 5 |
| Lexer.Lexer(String) | 0 | 1 | 1 | 1 |
| Lexer.getNumber() | 2 | 1 | 3 | 3 |
| Lexer.next() | 8 | 2 | 7 | 8 |
| Lexer.now() | 0 | 1 | 1 | 1 |
| MainClass.main(String[]) | 6 | 1 | 4 | 4 |
| Mono.Mono(BigInteger, BigInteger, BigInteger, Poly) | 6 | 1 | 4 | 4 |
| Mono.addCoe(BigInteger) | 0 | 1 | 1 | 1 |
| Mono.deepCopyMono(Mono) | 1 | 1 | 2 | 2 |
| Mono.equals(Object) | 4 | 3 | 4 | 6 |
| Mono.findClosingBracket(String, int) | 7 | 5 | 3 | 5 |
| Mono.getCoe() | 0 | 1 | 1 | 1 |
| Mono.getExpExp() | 0 | 1 | 1 | 1 |
| Mono.getExpPoly() | 0 | 1 | 1 | 1 |
| Mono.getVarExp() | 0 | 1 | 1 | 1 |
| Mono.getWholeExpPoly() | 0 | 1 | 1 | 1 |
| Mono.hashCode() | 0 | 1 | 1 | 1 |
| Mono.isFactor(String) | 5 | 3 | 7 | 7 |
| Mono.isMonoZero() | 0 | 1 | 1 | 1 |
| Mono.mulMono(Mono, Mono) | 3 | 2 | 2 | 3 |
| Mono.setCoe(BigInteger) | 0 | 1 | 1 | 1 |
| Mono.toString() | 27 | 7 | 14 | 17 |
| Numfactor.Numfactor(BigInteger, BigInteger) | 0 | 1 | 1 | 1 |
| Numfactor.toPoly() | 1 | 1 | 2 | 2 |
| Numfactor.todxPoly() | 0 | 1 | 1 | 1 |
| Pair.Pair(BigInteger, BigInteger, Poly) | 6 | 1 | 4 | 4 |
| Pair.deepCopyPair(Pair) | 1 | 1 | 2 | 2 |
| Pair.equals(Object) | 4 | 3 | 3 | 5 |
| Pair.getExpExp() | 0 | 1 | 1 | 1 |
| Pair.getExpPoly() | 0 | 1 | 1 | 1 |
| Pair.getVarExp() | 0 | 1 | 1 | 1 |
| Pair.hashCode() | 0 | 1 | 1 | 1 |
| Parser.Parser(Lexer) | 0 | 1 | 1 | 1 |
| Parser.isNum(String) | 3 | 3 | 2 | 3 |
| Parser.parseExpr() | 7 | 1 | 6 | 6 |
| Parser.parseExprFactor() | 5 | 1 | 4 | 4 |
| Parser.parseFactor() | 7 | 7 | 7 | 7 |
| Parser.parseFuncFactor() | 1 | 1 | 2 | 2 |
| Parser.parseTerm(int) | 4 | 1 | 4 | 4 |
| Parser.processPow(Lexer) | 5 | 2 | 4 | 4 |
| Poly.Poly() | 0 | 1 | 1 | 1 |
| Poly.addAllMono() | 10 | 3 | 6 | 7 |
| Poly.addMono(Pair, Mono) | 2 | 1 | 2 | 2 |
| Poly.addPoly(Poly) | 30 | 3 | 14 | 14 |
| Poly.deepCopyPoly(Poly) | 3 | 1 | 3 | 3 |
| Poly.divconstPoly(Poly, BigInteger) | 3 | 1 | 3 | 3 |
| Poly.equals(Object) | 10 | 7 | 5 | 10 |
| Poly.getConstPoly(BigInteger) | 1 | 2 | 2 | 2 |
| Poly.getGcd() | 10 | 4 | 4 | 5 |
| Poly.getZeroPoly() | 0 | 1 | 1 | 1 |
| Poly.hashCode() | 0 | 1 | 1 | 1 |
| Poly.isPolyZero() | 0 | 1 | 1 | 1 |
| Poly.mulPoly(Poly) | 16 | 2 | 8 | 8 |
| Poly.negate() | 3 | 1 | 3 | 3 |
| Poly.polyString(ArrayList) | 26 | 3 | 9 | 10 |
| Poly.powPoly(BigInteger) | 4 | 3 | 3 | 4 |
| Poly.toString() | 1 | 1 | 2 | 2 |
| Powerfactor.Powerfactor(BigInteger) | 0 | 1 | 1 | 1 |
| Powerfactor.toPoly() | 0 | 1 | 1 | 1 |
| Powerfactor.todxPoly() | 1 | 2 | 2 | 2 |
| Processor.delBlank(String) | 4 | 1 | 3 | 4 |
| Processor.processSymbol(String) | 2 | 1 | 5 | 5 |
| Term.Term(int) | 0 | 1 | 1 | 1 |
| Term.addFactor(Factor) | 0 | 1 | 1 | 1 |
| Term.setSign(int) | 0 | 1 | 1 | 1 |
| Term.toPoly() | 2 | 1 | 3 | 3 |
| Term.todxPoly() | 8 | 1 | 5 | 5 |
生成测试数据时,我们仍然使用递归下降的思想:
import random
import sympy
RANGE = 5
Addsign = 0
symbol = "+-*^x"
def gener_E(flag): # 表达式是否在括号内
if flag:
s = gener_T(True)
num = random.randint(0, RANGE)
for i in range(num):
s += "+" + gener_T(True)
else:
s = gener_T(False)
num = random.randint(0, RANGE)
for i in range(num):
s += "+" + gener_T(False)
return s
def gener_T(flag):
if flag:
s = gener_F(True)
num = random.randint(0, RANGE)
for i in range(num):
s += "*" + gener_F(True)
else:
s = gener_F(False)
num = random.randint(0, RANGE)
for i in range(num):
s += "*" + gener_F(False)
return s
def gener_F(flag):
F_list = [gener_F_num, gener_F_pow, gener_F_expr] # 函数列表
if flag:
choice = random.randint(0, len(F_list) - 2)
else:
choice = random.randint(0, len(F_list) - 1)
return F_list[choice]()
def gener_F_num():
num = random.randint(-11, 11)
return str(num)
def gener_F_pow():
exp = random.randint(0, 8)
return "x^+" + str(exp)
def gener_F_expr():
exp = random.randint(0, 8)
return "("+gener_E(True)+")^" + str(exp)
def addZero(s):
new_strng = ""
for i in range(len(s)):
if i > 0 and s[i-1] in symbol and s[i].isdigit():
num_zeros = random.randint(1, 3)
zeros = "0" * num_zeros
new_strng += zeros + s[i]
else:
new_strng += s[i]
return new_strng
def getBlank():
blank = random.randint(0, 1)
return " " if blank == 0 else "\t"
def addBlank(s):
new_string = ""
add = random.randint(0, 2)
for i in range(len(s)):
if i>0 and not s[i-1].isdigit() and not s[i].isdigit():
new_string += s[i] if add < 2 else getBlank() + s[i]
else:
new_string += s[i]
return new_string
s = gener_E(False)
s_add = addZero(s)
s_complete = addBlank(s_add)
print(s)
print(len(s))
print(s_complete)
print(len(s_complete))
第二次互测在输出时没有对exp的0进行特判导致错误
主要出错原因是在编写Mono.toString 方法的时候没有考虑周全,也没有进行充足的测试。
-1*x -> -x在第一次作业优化的前提下,添加提取公因数和判断是否需要双括号
String expr = this.wholeExpPoly.toString();
BigInteger gcd = this.wholeExpPoly.getGcd();
if (isFactor(expr)) {
expString = "e(" + expr + ")";
} else if (gcd.compareTo(BigInteger.ONE) != 0) {
Poly gcdPoly = Poly.divconstPoly(this.wholeExpPoly, gcd);
if (isFactor(gcdPoly.toString())) {
expString = "e(" + gcdPoly.toString() + ")" + "^" + gcd.abs();
} else {
expString = "e((" + gcdPoly.toString() + "))" + "^" + gcd.abs();
}
} else {
expString = "e((" + expr + "))";
}
如果要用一句话概括这一个月的迭代,那就是“痛并快乐着”。既痛苦于复杂的迭代,痛苦于初探索时混乱的代码,也快乐于一月以来的进步,惊喜于重构后的柳暗花明。从一月之前还不明白什么是递归下降,到现在已经可以写出解析表达式的复杂代码,痛苦挣扎的背后是肉眼可见的进步。在随后的三个月,我们还将继续迎接疼痛,也期待着疼痛背后的欣喜和快乐。