301
社区成员
发帖
与我相关
我的任务
分享三次作业总体上都是在解决一个问题:读入一个单变量(即x)表达式,输出恒等变形展开所有括号后的表达式。只是在每一次迭代中新增了一些算子如求导、exp指数函数、自定义函数等。
总体上我的处理思路分为两步:
1.将表达式化简成后缀表达式字符串。 eg:(x+1)*(x+2) -> x 1 + x 2 + *
2.将后缀字符串作为参数传入计算类中进行计算。
即 从左到右遍历,读到操作数就压栈,读到运算符就从栈顶取出对应的元素计算出结果并压入栈中
(当然,这里的运算符不仅可以是 + - * ^等,也可以把exp视为单目运算符
例如:exp(x^2) -> x 2 ^ exp 这样就可以解决第二次作业的新增内容
dx即求导算子也是同理)
首先,题目最基本的要求是要把不必要的括号全部展开,所以如何展开括号呢?课题组的第一单元的训练题中提供了两种思路:正则匹配和递归下降,考虑到后续有多重括号嵌套,递归下降显然是更优选。
关于递归下降的理解,建议看oo公众号中的文章并结合第一单元训练提供的代码,还是很容易理解的。
我们发现表达式可以有无限多的空白字符、冗余的正负号,难道要用lexer一个一个读过去吗?这样是麻烦且容易出bug的,所以可以对传入的表达式先进行预处理,再进行展开,以下是我的预处理思路:
1.删除全部空白字符
2.如果表达式第一个字符是符号位,补一个0
3.除去冗余的+、-号。 eg:+ -1 -> -1
4.^+ -> ^
5.* + -> *
6. -x -> -1*x
具体怎么预处理还要看你的后缀表达式是怎么去算的,这里只提供部分思路,可以根据自己的处理思路选择对应的预处理方法。
读入一个包含加、减、乘、乘方以及括号(其中括号的深度至多为 1 层)的单变量表达式,输出恒等变形展开所有括号后的表达式。

这里我的目的是要变成后缀式,因此重写每个类的toString方法,使其变为后缀表达式,上层类调用下层类的toString从而实现完整后缀表达式的展开
我们发现expr项与项之间有+/-号连接,这里我使用了两个arraylist,一个存项,一个存符号:
private final ArrayList<String> ops;//符号
private final ArrayList<Term> terms;//各个项
这里用到2个类来处理:分别是:
1.Oper类:负责对后缀表达式进行遍历计算
2.Poly类:规范类,HW-1中我们可以很容易的得出:标准答案的每一项一定长成这样子"a*x^b",因此用poly类(即多项式类)来规范计算过程
Poly中实现 add、sub、mul、pow方法,在oper中即可运用这些方法进行计算。

1.bug:本次有一个bug,主要还是预处理的问题,没把-x -> -1*x ,导致遇到 -x ^2,会把-x当作整体,错误输出 x ^ 2 的答案
2.hack:用python写了一个数据生成器加自动评测机,每个同学的代码跑个几千次,也是找到了一些bug,错误主要也是预处理部分的问题。
Ps:自动评测部分建议参考往届宁然学长的博客和b站视频,讲的很详细。
1.本次作业支持嵌套多层括号。
2.本次作业新增指数函数因子,指数函数括号内部包含任意因子。
3.本次作业新增自定义函数因子,但自定义函数的函数表达式中不会调用其他自定义函数。
1.多层括号如果使用的是递归下降可以直接跳过,正则匹配我也不会
2.增加exp类存放指数函数因子
3.对自定义函数的处理思路:
(1)增加Function类,在parser中添加hashmap属性来管理自定义函数我这里采用边递归下降边展开自定义函数的思路。
//在paserfactor中新增:
if(f||g||h){
}
//parser
private final Map<String, Function> funcs = new HashMap<>();//函数
(2)Function类中写方法进行形参和实参的替换,将实参作为参数传入,return替换后的经过parser的表达式即可。

1.bug:强测错了一个,原因是用int存储指数,但是可能会超过int范围,改为用BigInteger存储即可
2.hack:使用cxc同学的公测平台进行debug,没有发现别人的bug。
1.本次作业支持求导操作,新增求导算子 。求导因子可以出现在很多位置,包括函数调用实参,指数函数内部等,注意考虑周全。
(为了限制难度,在输入中,求导算子不会在自定义函数中出现)
2.本次作业函数表达式中支持调用其他“已定义的”函数(保证不会出现递归调用)
//Poly
public static Poly der(Poly a) throws CloneNotSupportedException {
//your code 实现求导
return Poly mypoly;
}

bug:这次的bug是预处理部分忘记把自定义函数内例如 f(+01,+01)中的两个+号去掉就直接进入parser了,而我的paser默认第一个一定是term,出现bug
hack:采用自己构造数据+使用评测机大量评测,未发现bug
希望课程组对性能优化部分给予更明确的指导,或者在第一单元训练中就给出可参考的代码(例如递归下降那样),否则没有一个明确的优化思路