个人作业1——四则运算题目生成程序

一、题目描述

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表

posted @ 2018-03-31 12:01  FantasyDream  阅读(367)  评论(0)    收藏  举报