第一章-第一题(小学生四则运算)--By郭青云
1.项目需求
a) 除了整数以外,还要支持真分数的四则运算。 (例如: 1/6 + 1/8 = 7/24)
b) 让程序能接受用户输入答案,并判定对错。 最后给出总共 对/错 的数量。
c) 逐步扩展功能和可以支持的表达式类型,最后希望能支持下面类型的题目 (最多 10 个运算符,括号的数量不限制)
25 - 3 * 4 - 2 / 2 + 89 = ?
1/2 + 1/3 - 1/4 = ?
(5 - 4 ) * (3 +28) =?
d) 一次可以批量出 100 道以上的题目,保存在文本文件中, 并且保证题目不能重复,
2.项目实现
a)开发环境
开发工具:MyEclipse、jdk1.8、windows 7
开发语言:Java
b)项目设计
1)主要UML图
2)主要代码
a.判断两个数是否互质
1 public static boolean isCoprime(int m,int n){
2 int a=0;
3 int b=0;
4 int c=0;
5 if(m > n) {
6 a = m;
7 b = n;
8 }else{
9 a=n;
10 b=m;
11 }
12 while((c = a % b) != 0) {
13 a = b;
14 b = c;
15 }
16 if(b==1){
17 return true;
18 }
19 return false;
20 }
b.分数约分
/**
* @param exp 单个分数表达式
* @returned String 返回约分后的分数表达式
* */
public static String afterSimplify(String exp){
String[] num=exp.split("/");
int cop=Integer.parseInt(num[0]);//分子
int deno=Integer.parseInt(num[1]);//分母
if(cop==0){//分子为0
return "0";
}
int max=0;
while(max!=1){
max=maxMultiple(cop, deno);//返回cop、deno的最大公约数
cop/=max;
deno/=max;
}
if(deno==1){
return cop+"";//分数值为1
}else{
return cop+"/"+deno;//化简后的分数
}
}
c.中缀表达式转化为后缀表达式
/**
* @param infix 中缀表达式
* @returned String 后缀表达式
* */
public static String infix2postfix(String infix){
String postfix="";
int length=infix.length();
Stack st = new Stack();
String c;
for (int i = 0; i < length; i++){
c = infix.substring(i, i+1);
if (c .equals("(")){
st.push(c);
}else if (c.equals(")")){
while (!st.peek().equals("(")){
postfix+= (st.pop()+"#");
}
st.pop();
}else{
try{
Integer.parseInt(c);//判断读到的字符是否为数字
for(int j=0;j<5;j++){//如读到数字,则继续向后读取,直到读到运算符为止
String c_temp="";
if((i+j+2)>length){//判断是否到达输入的字符串的结尾
break;
}
c_temp=infix.substring(i+j+1,i+j+2);
try {
Integer.parseInt(c_temp);//判断独到的字符是否为数字
c+=c_temp;
continue;
} catch (Exception e) {
break;
}
}
i+=(c.length()-1);
postfix+= (c+"#");
}catch(Exception e){
while (!st.empty()&& (comparePri((String)st.peek(), c) >= 0)){
postfix += (st.pop()+"#");
}
st.push(c);
}
}
}
while (!st.empty()){//输入栈中剩余的所有元素
postfix +=(st.pop()+"#");
}
return postfix;
}
/**
*@param op1 op2 运算符
*@return int op1、op2的优先级比较结果
* */
public static int comparePri(String op1, String op2){
if (op1 .equals("(")){
return -1;
}else if (op1 .equals("+") || op1 .equals("-")){
if (op2.equals("*") || op2.equals("/")){
return -1;
}
}else if (op1 .equals("*") ||op1 .equals("/")){
if (op2 .equals("+") || op2 .equals("-")){
return 1;
}
}
return 0;
}
d.表达式求值(整式和分式)
/**
* @param exp 四则运算表达式
* @return 表达式元算结果的最简(分数)形式
* */
public String calculate(String exp){
int a,b,result=0;
String first,second,temp = "";
int first_cop,first_deno,second_cop,second_deno;
Stack s=new Stack();
String[] c=exp.split("#");
//分式求值
if(exp.contains("/")){
for(int i=0;i<c.length;i++){
if(!(c[i].contains("+")||c[i].contains("-")||c[i].contains("*")||c[i].contains("/"))){
s.push(c[i]+"/1");//将整数化为分母为1的分数形式
continue;
}else{
second=(String) s.pop();
first=(String) s.pop();
first_cop=Integer.parseInt(first.split("/")[0]);//第一个分数的分子
first_deno=Integer.parseInt(first.split("/")[1]);//第一个分数的分母
second_cop=Integer.parseInt(second.split("/")[0]);//第二个分数的分子
second_deno=Integer.parseInt(second.split("/")[1]);//第二个分数的分母
if(c[i].equals("+")){//分数相加
temp=(first_cop*second_deno+second_cop*first_deno)+"/"+(first_deno*second_deno);
}else if(c[i].equals("-")){//分数相减
temp=(first_cop*second_deno-second_cop*first_deno)+"/"+(first_deno*second_deno);
}else if(c[i].equals("*")){//分数相乘
temp=(first_cop*second_cop)+"/"+(first_deno*second_deno);
}else if(c[i].equals("/")){//分数相除
temp=(first_cop*second_deno)+"/"+(first_deno*second_cop);
}
s.push(temp);//将计算结果压入栈中
}
}
//将最终结果约分后返回
return Simplify.afterSimplify((String) s.pop());
}else{
//整式求值
for(int i=0;i<c.length;i++){
try{
Integer.parseInt(c[i]);//判断是否为数字
s.push(c[i]);
continue;
}catch(Exception e){
b=Integer.parseInt((String) s.pop());
a=Integer.parseInt((String) s.pop());
if(c[i].equals("+")){
result=a+b;
}else if(c[i].equals("-")){
result=a-b;
}else if(c[i].equals("*")){
result=a*b;
}
s.push(result+"");
}
}
}
//返回整数运算结果
return result+"";
}
e.随机生成纯整式、纯分式、混合表达式
if(type.equals("1")){//整式运算
for (int i = 0; i < count; i++) {//生成count个正式
questions.add(b.zhengshi(min, max));
}
}else if(type.equals("2")){//分式运算
for (int i = 0; i < count; i++) {//生成count个分式
questions.add(b.fenshi(deno));
}
}else if(type.equals("3")){//混合运算
for (int i = 0; i < count; i++) {//生成count个混合元算表达式
int length=r.nextInt(4)+3;//新加的符号个最最多为6个
String op,exp="";
for(int j=0;j<length;j++){
op=ops[r.nextInt(2)];//随机选取运算符号 '+'或'*'
if(op.equals("+")){
if(r.nextInt(2)==1){
exp=exp+b.zhengshu(min, max)+"+";
}else{
exp=exp+b.fenshu(deno)+"+";
}
}else if(op.equals("*")){
if(exp.length()==0){
exp=r.nextInt(9)+2+"+";
}
if(r.nextInt(2)==1){//随机选取整式或整数
String item=b.zhengshi(min, max);
while(item.contains("*")||item.contains("/")){
item=b.zhengshi(min, max);
}
item="("+item+")";
if((exp.substring(0,exp.length()-1).contains("+")||exp.substring(0,exp.length()-1).contains("-"))
&&!exp.substring(0,exp.length()-1).contains("*")
&&!exp.substring(0,exp.length()-1).contains("/")){
exp="("+exp.substring(0,exp.length()-1)+")*"+item+"+";
}else{
exp=exp.substring(0,exp.length()-1)+"*"+item+"+";
}
}else{
String item=b.zhengshu(min, max);
if((exp.substring(0,exp.length()-1).contains("+")||exp.substring(0,exp.length()-1).contains("-"))
&&!exp.substring(0,exp.length()-1).contains("*")
&&!exp.substring(0,exp.length()-1).contains("/")){
exp="("+exp.substring(0,exp.length()-1)+")*"+item+"+";
}else{
exp=exp.substring(0,exp.length()-1)+"*"+item+"+";
}
}
}
}
if(!exp.equals("")&&(exp.subSequence(exp.length()-1, exp.length()).equals("+"))){
exp=exp.substring(0,exp.length()-1);//剔除表达式末尾的加号
}
f.题目重复性检测
public class CheckRepeat { /** *@author GuoQingYun *@param list 以生成的题目组成的集合,集合呢各题均不重复 *@param exp 新生成的待检测的表达式 *@param BaseGenerator的对象 *@return true-新生成的表达式与之前的重复 false-新生成的表达式与之前的不重复 * */ public static boolean check(List list,String exp,BaseGenerator b){ String latterVal=b.calculate(Convert.infix2postfix(exp)); List formorOperator=new ArrayList(); List latterOperator=new ArrayList(); List formorNumber=new ArrayList(); List latterNumber=new ArrayList(); for(int i=0;i<list.size();i++){ //判断两个表达式的计算结果是否相等 if(b.calculate(Convert.infix2postfix(list.get(i).toString())).equals(latterVal)){ formorOperator=extractOperator(list.get(i).toString()); latterOperator=extractOperator(exp); //判断两个表达式的运算符合是否完全一一匹配 if(compare(formorOperator, latterOperator)){ formorNumber=extractNumber(list.get(i).toString()); latterNumber=extractNumber(exp); //判断两个表达式中包含的整数项是否完全一一匹配 if(compare(formorNumber, latterNumber)){ return true; } } } } return false; } /** * @author GuoQingYun * @param exp -四则运算表达式 * @return List -从表达式exp中分解出来的所有运算符的集合 * */ public static List extractOperator(String exp){ List operator=new ArrayList(); String c=""; exp=exp.replace("(", "");//剔除掉表达中包含的括号 exp=exp.replace(")", ""); for (int i = 0; i < exp.length(); i++) { c=exp.substring(i,i+1);//逐个扫描表达式中的字符 if(c.equals("+")||c.equals("-")||c.equals("*")||c.equals("/")){ operator.add(c); } } return operator; } /** * @author GuoQingYun * @param exp -四则运算表达式 * @return List -从表达式exp中分解出来的所有整数的集合 * */ public static List extractNumber(String exp){ List number=new ArrayList(); String c=""; exp=exp.replace("(", "");//剔除掉表达式中包含的括号 exp=exp.replace(")", ""); for (int i = 0; i < exp.length(); i++) { c=exp.substring(i,i+1); for(int j=0;j<5;j++){//如读到数字,则继续向后读取,直到读到运算符为止 String c_temp=""; if((i+j+2)>exp.length()){//判断是否到达输入的字符串的结尾 break; } c_temp=exp.substring(i+j+1,i+j+2); try { Integer.parseInt(c_temp);//判断独到的字符是否为数字 c+=c_temp; continue; } catch (Exception e) { break; } } i+=(c.length()-1); number.add("c"); } return number; } /** * @author GuoQingYun * @param formor -以存在的与其他表达式不重复的表达式中包含的运算符或整数的集合 * @param latter -新生成的表达式中包含的运算符或整数的集合 * @return boolean -true:formor与latter元素种类个元素个数完全匹配 * -false:formor与latter元素种类个元素个数不完全匹配 * */ public static boolean compare(List formor,List latter){ if(formor.size()!=latter.size()){ //两个表达式运算符或整数项不是一一匹配 return false; }else{ for(int i=0;i<formor.size();i++){ if(formor.contains(latter.get(i))){ formor.remove(latter.get(i));//剔除掉已经比较过的项 latter.remove(i); continue; }else{ //两个表达式的运算符或整数项不是一一匹配 return false; } } //两个表达式的运算符或整数项一一匹配 return true; } } }
c)测试结果
1)整式运算
2)分式运算
3)混合运算
3.总结
目前各项需求已基本达成,实验结果也比较令人满意。但也有不足之处,比如:题目生成规则优待有待改善等。这些问题将会在下一阶段逐步解决。