目录
写在前面
对于自己而言,这学期的面向对象课程是一次地狱般的磨练。因为上学期没有学习OO Pre的课程,寒假时的预习也并不巩固,导致实际上手Java编写程序时感到举步维艰。尽力尝试了hw1但最终没能通过公测,于是hw2和hw3遂罢,将自己的学习重心放在熟悉Java细节,只得在Unit 2再努力拼搏了。
因此,实际上这篇博客肯定无法按照课程组的要求完成了,但我还是希望能够对这个单元的学习进行简单的总结。虽然没有哪怕一次作业通过,我认为自己还是学到了一些新的知识,相信这对我后续的学习也有很多的帮助作用。
作业分析
hw1架构设计
我将读取到的输入按照不同的形式化表达分为不同的类,Expr为表达式类,Number为常数类,Exprfactor为表达式因子类,Variable为变量类,Term为项类。此外还有Lexer字符读取类和Parser表达式解析类。在Parser类中利用递归下降的算法对输入的表达式进行解析。
递归下降算法
import java.math.BigInteger;
public class Parser{
private final Lexer lexer;
public Parser(Lexer lexer) {
this.lexer = lexer;
}
public Expr parseExpr(){//表达式层面
Expr expr = new Expr();
char mark = '+';
if (lexer.peek().equals("+") || lexer.peek().equals("-")) {
mark = lexer.peek().charAt(0);
lexer.next();
}
expr.addTerm(parseTerm(), mark);
while(lexer.peek().equals("+") || lexer.peek().equals("-")){
mark = lexer.peek().charAt(0);
lexer.next();
expr.addTerm(parseTerm(), mark);
}
return expr;
}
public Term parseTerm(){//项层面
Term term = new Term();
term.addFactor(parseFactor());
while(lexer.peek().equals("*")){
lexer.next();
term.addFactor(parseFactor());
}
return term;
}
public Factor parseFactor(){//因子层面
if ("0123456789+-".contains(lexer.peek())){//取出一个常数因子
char mark = '+';
if(lexer.peek().equals("+") || lexer.peek().equals("-")){
mark = lexer.peek().charAt(0);
lexer.next();
}
BigInteger value = new BigInteger(lexer.peek());
lexer.next();
return new Number(value, mark);
}
else if(lexer.peek().equals("(")){
lexer.next();
Expr expr = parseExpr();
lexer.next();
BigInteger exp = new BigInteger("1");
if(lexer.peek().equals("**")){
lexer.next();
if(lexer.peek().equals("+")){
lexer.next();
}
exp = new BigInteger(lexer.peek());
lexer.next();
}
Exprfactor exprfactor = new Exprfactor(expr, exp);
return exprfactor.expand(exprfactor, exp);
}
else{//变量指数因子
String variable = lexer.peek();
lexer.next();
BigInteger exp = new BigInteger("1");
if(lexer.peek().equals("**")){
lexer.next();
if(lexer.peek().equals("+")){
lexer.next();
}
exp = new BigInteger(lexer.peek());
lexer.next();
}
return new Variable(variable, exp);
}
}
}
在测试时出现的问题主要在于展开表达式因子的括号时,没有找到太好的方法去进行逐项相乘,这一点经过同学点播后,已经明白了可以直接开一个储存该表达式因子中所有项的ArrayList,再进行循环索引的展开。
复杂度分析
复杂度分析的结果不出所料,parseFactor方法的复杂度数据较大,这是因为在分析时,Factor类型的字符串数量较多,且作为递归下降的终点,解析的次数也会相应增加。
对类的分析
1.Expr类
作为最顶层元素和递归下降的起点,包含了对项的添加方法,和重写的toString方法。
2.Exprfactor类
递归下降的关键步骤,要将其看作一因子类型,其中包含expand括号展开方法,对项的添加方法和重写的toString方法。
3.Lexer类
其结构同训练课内容,包含了peek方法用于读取当前字符和next方法用于读取下一字符。
4.Number类
常数因子类,具体而言就是重写的toString方法将其返回。
5.Parser类
递归下降的核心类,是字符表达式的解析器。包含了三个解析方法,分别是对项的解析parseTerm方法,对因子的解析parseFactor方法和对表达式的解析parseExpr方法,用于通过递归下降算法实现对全部括号的展开。
6.Term类
由于所有项都是由因子组成,因此设置了addFactor方法用于向其中添加因子,和重写的toString方法。
7.Variable类
变量因子类,处理方法较为简单,只需要根据输入的变量和指数重写toString方法再加入Term即可。
关于hw1的反思和总结
说实话,由于没有学习OO Pre课程,我对于第一单元要学习和练习的内容可谓一无所知。即便如此,在助教和同学们的帮助下,我对于递归下降的理解也能够掌握得比较透彻,基本的思路架构也都较为完善。可惜在处理的细节上还是没能做到很好,有一种临门一脚没能完成的遗憾感。因此我希望自己的遗憾能在后面的学习中弥补回来。
hw2和hw3的一些小想法
在递归下降的基础上,添加的功能都可以通过识别首字母进行特殊的判断而不产生冲突,不妨将他们全部归入Factor类中,再进行特殊的处理。
三角函数因子相对比较简便,其求导也可以通过新增两个类进行互换转化。而自定义函数的实现我觉得可以通过先识别后替换的方法进行带入,之后再考虑去括号和求导的方法。
当然上述都是一些自己不成熟的想法思路,其具体实现只能等闲暇之时再进行探究了。
bug分析
遗憾没能过公测,程序的算法并不完善,因此这部分内容只好跳过。
心得体会
正如我开头所言,面向对象的第一单元对我而言并不友好,我实在是没有很强的编程能力和速学能力,因此没有学习OO Pre实在是非常大的错误和遗憾。但还是感谢助教对我的鼓励和同学对我的帮助,没有他们的陪伴我更是无法看到前路。
尽管作业最终成了一地鸡毛,不过我还是初步体会到了面向对象设计的大致思想,化繁为简、化整为零的编程习惯值得我进一步进行体会。
接下来就是破釜沉舟的战斗了,希望我能够好运。