一、题目描述
1.随机生成指定数量的不重复的四则运算表达式
2.表达式的数字范围也可指定
3.将生成的题目输出到文件上
4.用户可回答问题,程序可查错
5.支持分数运算,答案也为分数
二、需求分析
用户选择生成题目后随机生成不重复的四则运算表达式并写入文件
用户填写答案到相应文件后选择检查答案可得到对错题目
四则运算支持分数答案
三、功能设计
1.用户选择功能 生成题目 提交题目 推出
2.选择生成题目后要求用户输入数字范围和题目数量
3.生成相应数量和数字范围的表达式并写入文件
4.用户在文件中答题后选择提交答案
5.程序返回答题的正确数目和错误数目。
四、代码说明
1.Num类
题目中所有的数都有Num类来表示。
Num类由分子和分母两个属性组成。
重写该类的toString方法,使其在输出时能根据情况输出为整数和分数。
其中,若表示的数为真分数时,需要对其进行约分,所以添加一个reduction方法进行约分
约分需要用到最大公约数,所以写一个递归函数getGCD来求分子分母的最大公约数,其中用到了辗转相除法。
在Num类中添加了一个静态方法count,用来进行Num对象之间的计算。
还添加了一个判断Num大小的静态方法max
最后添加了一个方法createNum,能随机生成Num
public String toString() {
if (this.denomenator == 1) {
return String.valueOf(this.numerator);
} else if (this.numerator > this.denomenator) {
if (this.numerator % this.denomenator == 0) {
return String.valueOf(this.numerator / this.denomenator);
} else {
return this.numerator / this.denomenator + "'" + this.numerator % this.denomenator + "/"
+ this.denomenator;
}
} else if (this.numerator < this.denomenator) {
return this.numerator + "/" + this.denomenator;
} else if (this.numerator == 0) {
return "0";
}
return "1";
}
2.Expression类
该类用来生成四则运算表达式,并对表达式进行后缀转换。
表达式用Arraylist来存储
添加createExpression方法用于表达式生成,原理为根据输入的运算发数目进行循环,每次循环生成一个Num和一个运算符存入数组,并随机添加括号,最后删除多余的运算符
添加toPRN方法用于将表达式转换为后缀表达式,原理为每次读到数字时放入数组中,读到符号时进栈,直到读到下个符号时判断优先级,若前一个优先级高,则出栈进数组,否则继续将新的符号进栈。若读到括号,则将括号后的所有符号进栈,直到读到“)”时,将“(”后的所有符号出栈。
其中isOperator用于判断是否为运算符,priority判断符号优先级,randomOperator用于生成随机运算符,toString用于将Arraylist转换为String。
public ArrayList<Object> createExpression(int operator_no, int edge) {
ArrayList<Object> expression = new ArrayList<Object>();
Random r = new Random();
int backet = 0;
int backet_no = 0;
for (int i = 1; i <= operator_no + 1; i++) {
backet = r.nextInt(3);
if (backet_no != 0 && backet != 0 && expression.get(expression.size() - 1) != "(") {
Num num = new Num();
num.randomNum(edge);
expression.add(num);
expression.add(")");
expression.add(randomOperator());
backet_no--;
}
else if (i != operator_no + 1) {
if (backet == 1) {
expression.add(0, "(");
++backet_no;
Num num = new Num();
num.randomNum(edge);
expression.add(num);
expression.add(randomOperator());
} else if (backet == 2) {
Num num = new Num();
expression.add("(");
++backet_no;
num.randomNum(edge);
expression.add(num);
expression.add(randomOperator());
} else {
Num num = new Num();
num.randomNum(edge);
expression.add(num);
expression.add(randomOperator());
}
} else {
Num num = new Num();
num.randomNum(edge);
expression.add(num);
expression.add(randomOperator());
}
}
expression.remove(expression.size() - 1);
while (backet_no != 0) {
expression.add(")");
backet_no--;
}
while (expression.get(0) == "(") {
backet = 0;
int bracket_leng = 0;
String o = "";
for (int j = 0; j < expression.size(); j++) {
o = expression.get(j).toString();
if (o == "(") {
backet++;
bracket_leng--;
}
if (o == ")") {
backet--;
bracket_leng--;
}
if (backet == 0 && bracket_leng != (2 * operator_no)) {
return expression;
}
if (backet >= 1) {
bracket_leng++;
}
}
if (bracket_leng == (2 * operator_no)) {
expression.remove(0);
expression.remove(expression.size() - 1);
}
}
return expression;
}
3.NumTree类
该类用于将后缀表达式存入二叉树中,有left,right,value,data四个属性,left存储左节点,right存储右节点,value存储该树的运算过后的结果,data为存储的值
createNumTree方法用于将后缀表达式建立为一个树,原理为每次读到Num类是将其建立为节点,并入栈;读到运算符时,将其建立为节点并将栈中的两个节点出栈,根据value判断大小,大的为左节点,小的为右节点,然后入栈。直到读入最后一个运算符时建树,返回建立的树。
max方法为判断两个树节点的大小,toString借用递归方法outPutTree将树转换为字符串。outPutTree用后序遍历的递归方法将树转换为字符串。
public NumTree createTree(ArrayList<Object> rpn) {
Stack<Object> stack = new Stack<Object>();
NumTree t = null;
Object ob;
for (int i = 0; i < rpn.size(); i++) {
t = new NumTree();
ob = rpn.get(i);
if (Expression.isOperator(ob.toString())) {
NumTree t2 = (NumTree) stack.pop();
NumTree t1 = (NumTree) stack.pop();
if (NumTree.max(t1, t2)) {
t.setData(ob.toString());
t.setLeft(t1);
t.setRight(t2);
t.setValue(Num.count(t1.getValue(), t2.getValue(), ob.toString()));
if (t1.getValue().getDenomenator() == 0) {
return new NumTree("0", t.getValue(),null, null );
}
} else {
t.setData(ob.toString());
t.setLeft(t2);
t.setRight(t1);
t.setValue(Num.count(t1.getValue(), t2.getValue(),ob.toString()));
if (t.getValue().getDenomenator() == 0) {
return new NumTree("0", t.getValue(), null, null);
}
}
stack.push(t);
} else {
t.setData(ob.toString());
t.setValue((Num) ob);
stack.push(t);
}
}
return t;
}
4.check类
用于在生成表达式时的查重,检查文件是否已存在和表达式答案是否符合格式
5.Main类
与用户进行交互的类,负责各个类的调用和输出内容到文件
五、代码
码云地址
https://gitee.com/fandre/arithmetic.git
六、测试




七、psp表
