一. 多项式求导问题描述
基本概念的声明:
-
带符号整数 支持前导 0 的带符号整数,符号可忽略,如:
+02
、-16
、19260817
等。 -
因子
- 变量因子
- 幂函数
- 一般形式 由自变量x和指数组成,指数为一个带符号整数,如:
x ^ +2
。且,指数绝对值一律不得超过$ {10}^4 $。 - 省略形式 当指数为1的时候,可以采用省略形式,如:
x
。
- 一般形式 由自变量x和指数组成,指数为一个带符号整数,如:
- 三角函数
sin(x)
,cos(x)
,另外,本指导书范围内所有的词语“三角函数”,除非特殊说明,否则一律包含且仅包含上述两个函数)- 一般形式 类似于幂函数,由
sin(x)
,cos(x)
和指数组成,指数为一个带符号整数,如:sin(x) ^ +2
。同样的,指数绝对值一律不得超过${10}^{4}$。 - 省略形式 当指数为1的时候,可以采用省略形式,省略指数部分,如:
sin(x)
。
- 一般形式 类似于幂函数,由
- 幂函数
- 常数因子 包含一个带符号整数,如:
233
。 - 表达式因子 将在表达式的相关设定中进行详细介绍。不过,表达式因子不支持幂运算。
- 嵌套因子 本次作业将支持因子嵌套在三角函数因子里面,即一个因子作为另一个三角函数因子的自变量,例如
sin(x^2)
,cos(sin(x))
以及sin(sin(cos(cos(x^2))))^2
等。但是不允许出现指数为变量的情况,指数依然只能是带符号整数,例如sin(x) ^ sin(x)
是不合法的,因为指数不是自变量。也不允许幂函数的自变量为除了x
之外的因子,例如1926^0817
是不合法的,因为幂函数的自变量只能为x
。
- 变量因子
-
项表达式 由加法和减法运算符等若干项组成,如:
(-1 + x ^ 233)* sin(x^2) ^ 06 - cos(sin(x)) * 3 * sin((x))
。此外,在第一项之前,可以带一个正号或者负号,如:- -1 + x ^ 233、+ -2 + x ^ 1926
。此处有几点注意:空白字符 在本次作业中,空白字符包含且仅包含<space>
和\t
。其他的除了上述会用到的字符之外,均属于非法字符。- 一般形式由乘法运算符连接若干任意因子组成,如:
x * cos(x) * x
,sin(x ^ 2) * cos(sin(x)) ^ 2 * x ^ -2
等。- 项内因子不仅仅是同类因子
- 特殊形式
- 第一个因子为常数因子 1 且其后跟着乘号的时候,可以省略该常数因子或表示为正号开头的形式,如:
x ^ 2 * x ^ -1
、+ x ^ 2
、+ cos(x) * cos(x)
、sin(x) * cos(x)
。 - 第一个因子为常数因子 -1 且其后跟着乘号的时候,可以表示为负号开头的形式,如:
-x ^ 2、- cos(x) * sin(x)
。
- 第一个因子为常数因子 1 且其后跟着乘号的时候,可以省略该常数因子或表示为正号开头的形式,如:
- 一般形式由乘法运算符连接若干任意因子组成,如:
-
-
表达式因子,表达式可以作为因子,其定义为被一对小括号包裹起来的表达式,即我们允许诸如
(x * cos(x))
这种式子的出现 -
空串不属于合法的表达式
-
二. 程序结构分析
1.类和方法设计综述
-
Polynomial: 控制输入输出,接受外部输入的字符串并将其传入Poly类中进行实际操作
public class Polynomial { public static void main(String[] args) { Scanner input = new Scanner(System.in); if (input.hasNextLine()) { String str = input.nextLine(); input.close(); if (str.trim().isEmpty()) { System.out.println("WRONG FORMAT!"); System.exit(0); } Poly p = new Poly(str); if (p.illegalString()) { System.out.println("WRONG FORMAT!"); } else if (p.irregularString()) { System.out.println("WRONG FORMAT!"); } else { p.output(); } } else { System.out.println("WRONG FORMAT!"); } } }
-
Poly
-
首先判断输入的字符串是否存在非法输入:非法字符、不该出现空白符的地方出现空白符。若输入的字符串符合输入规则,则将空白符号去掉。
-
按照表达式的构成规则将字符串分割为项,同时初始化一个Experssion类存储当前的表达式
-
按照项的构成规则将字符串分割为因子,同时初始化一个Factor类存储当前的项
-
按照因子的不同种类分别求出该因子的底数与指数,同时初始化一个Item类存储当前因子
(若2,3,4步出现不该出现的情况则返回true,程序输入“WRONG FORMAT!”并推出)
public boolean illegalString() {
...
}
public boolean findExpression(final int begin, final int end,
final Expression curExp) {
Factor fac = new Factor();
if (judgeFactor(i, j, fac)) {
return true;
}
....
}
public boolean judgeFactor(int left, int right, Factor fac) {
Item ite = new Item();
if (judgeItem(i, j, ite, leftTmp + 1)) {
return true;
}
fac.getFactors().add(ite);
....
}
public boolean judgeItem(final int left, final int right, final Item ite,
final int begin) {
....
}
-
Item
public class Item { private BigInteger coe; private BigInteger idx; private BigInteger curCoe; private BigInteger curSelfcoe; private int type; private int variableX = 0; private ArrayList<Expression> chain = new ArrayList<Expression>(); public String getDerivation() { .... } public String getSelf() { .... }
-
Factor
public class Factor { private int op; private ArrayList<Item> factors = new ArrayList<Item>(); public String getDerivation() { .... } public String getSelf() { .... }
-
Expression
public class Expression extends Item { private ArrayList<Factor> expression = new ArrayList<Factor>(); public ArrayList<Factor> getExp() { return this.expression; } public String getDerivation() { .... } public String getSelf() { .... }
Expression, Factor, Item中均有getSelf和getDerivation方法,以此实现链式求导。
2.UML图展示
3.优缺点分析
优点:
-
-
在最开始设计时按照多项式,项,因子层层递进的思想设计使得后续作业改动较小
-
按要求进行链式法则求导设计,减少了繁琐的求导过程
-
合理地将重复使用的函数封装为方法,减少了工作量。
-
缺点:
-
-
在最后一次作业中并没有进行大规模的优化,但其实可以做一下简单的同类项合并
-
在处理输入时应当适当运用正则表达式,这样可以减少一部分工作量,否则就会出现在对输入进行判断时出现大量布尔表达式的情况
-
代码风格仍然有待提高。
-
在阅读指导书时要认真仔细否则会导致细节失分严重。
-
三. 程序问题总结- -未通过的样例及其原因分析
未通过样例 | 原因分析 |
++641310706398282959093109711020261029178921763*x^-7100862071031683371053510210321531010574509245101-+29457694746621086265146643351091037558161089*x^+29457694746621086265146643351091037558161089。。。 | 在阅读指导书时要仔细,注意在指导书中已经暗示会出现大数,因此应该在所有指数和系数出现的地方均用BigInteger进行记录 |
(((((((((((((((((((-4*cos(x)^3+3*cos(x))))))))))))))))))))) | 没有考虑括号的嵌套(默认表达式由一对括号括起来) |
++(sin(x)) | 忘记考虑多项式因子前也可以将1省略为+ |
四. 对象创建模式分析
总的来讲,设计模式可分为三类
- 创建型模式:对象实例化的模式,创建型模式用于解耦对象的实例化过程。
- 结构型模式:把类或对象结合在一起形成一个更大的结构。
- 行为型模式:类和对象如何交互,及划分责任和算法。
借鉴博客:https://www.cnblogs.com/pony1223/p/7608955.html 中的示意图可将23种设计模式表示如下:
目前已经在课上接触过得模式大体有五种:
- 单例模式:某个类只能有一个实例,提供一个全局的访问点。
- 简单工厂:一个工厂类根据传入的参量决定创建出那一种产品类的实例。
- 工厂方法:定义一个创建对象的接口,让子类决定实例化那个类。
- 抽象工厂:创建相关或依赖对象的家族,而无需明确指定具体类。
- 建造者模式:封装一个复杂对象的构建过程,并可以按步骤构造。
以第三次作业为例,可以粗略将第三次作业归为工厂模式,但实际的程序设计仍与工厂模式有一定差异。在第三次作业种,Expression,Facotr以及Item均实现了getSelf以及getDeriviation方法,但每个类中的这两种方法又存在一定差异。希望在之后的程序设计种能够更好地遵循标准设计模式
五. 心得体会
1. 第一部分的作业相对难度不是很大,可能是因为还没有到多线程部分,但仍然提醒我要注意细节,否则因为细节失分不划算。
2. 由于之前利用java编程较少,因此前三次作业也是对java编程语言学习的很好机会。
3.逐渐体会到面向对象编程设计的思想和方法,希望之后在之后的作业中能继续努力。