个人作业1——四则运算题目生成程序(基于控制台)

 

一、需求分析


 

  1. 自动生成与输入变量对应的数量与范围的四则运算题目,并保留答案与练习本(txt)
  2. 生成的题目中如果存在形如e1 ÷ e2的子表达式,那么其结果应是真分数
  3. 每道题目中出现的运算符个数不超过3个。
  4. 程序一次运行生成的题目不能重复,即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。
    生成的题目存入执行程序的当前目录下的Exercises.txt文件,格式如下:
         1. 四则运算题目1
         2. 四则运算题目2
              ……其中真分数在输入输出时采用如下格式,真分数五分之三表示为3/5,真分数二又八分之三表示为2’3/8。
  5. 在生成题目的同时,计算出所有题目的答案,并存入执行程序的当前目录下的Answers.txt文件,格式如下:
        1. 答案1
        2. 答案2
  6. 程序支持对给定的题目文件和答案文件,判定答案中的对错并进行数量统计,并会输出所有题目中重复的题目

二、PSP


PSP2.1 Personal Software Process Stages Time Senior Student Time  
Planning 计划 2 2  
· Estimate 估计这个任务需要多少时间 4 8  
Development 开发 1 2  
· Analysis 需求分析 (包括学习新技术) 2 3  
· Design Spec 生成设计文档 0 0  
· Design Review 设计复审 0 0  
· Coding Standard 代码规范 0 0  
· Design 具体设计 0 0  
· Coding 具体编码 2 1  
· Code Review 代码复审 0 0  
· Test 测试(自我测试,修改代码,提交修改) 2 4  
Reporting 报告 NaN NaN  
· 测试报告 NaN NaN  
· 计算工作量 NaN NaN  
· 并提出过程改进计划 NaN NaN

 


 三、关键代码

  关于题目不重复的实现:比较蛋疼的要求,我第一个想到的是set子类HashSet,考虑将中序、后序表达式存入,比较两次确定唯一,然而bug居多,无奈网上找了关于二叉树的实现,感觉还行

  首先是搭一个栈:

  

public class Stacks {
	private LinkedList<Object> list = new LinkedList<Object>();
	public int top = -1;

	public void push(Object value) {
		top++;
		list.addFirst(value);
	}

	public Object pop() {
		Object temp = list.getFirst();
		top--;
		list.removeFirst();
		return temp;
	}

	public Object top() {
		return list.getFirst();
	}

	public Iterator<Object> iterator(){
		Iterator<Object> itr = list.iterator();
		return itr;	
	}
}

  以及后缀表达式的构建与计算

public ArrayList<Object> toRPN(ArrayList<Object> list) {
            ArrayList<Object> right = new ArrayList<Object>();// 存储右序表达式
            Stacks aStack = new Stacks();//
            String operator;
            int position = 0;// 当前指针位置
            while (true) {
                // 当前指针为符号
                if (isOperator(list.get(position).toString())) {
                    // 栈为空,或指针为(,直接进栈
                    if (aStack.top == -1
                            || ((String) list.get(position)).equals("(")) {
                        aStack.push(list.get(position));
                    } else {
                        // 指针为)
                        if (((String) list.get(position)).equals(")")) {
                            // 将栈内(后的运算符出栈
                            while (true) {
                                if (aStack.top != -1
                                        && !((String) aStack.top()).equals("(")) {
                                    operator = (String) aStack.pop();
                                    right.add(operator);
                                } else {
                                    if (aStack.top != -1)
                                        aStack.pop();
                                    break;
                                }
                            }
                        } else {
                            while (true) {
                                // 栈不为空,判断优先级
                                if (aStack.top != -1
                                        && priority((String) list.get(position),
                                                (String) aStack.top())) {
                                    operator = (String) aStack.pop();
                                    if (!operator.equals("("))
                                        right.add(operator);
                                } else {
                                    break;
                                }

                            }
                            aStack.push(list.get(position));
                        }
                    }
                }
                // 数字入栈
                else {
                    right.add(list.get(position));
                }
                position++;
                if (position >= list.size())
                    break;
            }
            // 栈内剩余运算符出栈
            while (aStack.top != -1) {
                operator = (String) aStack.pop();
                if (!operator.equals("("))
                    right.add(operator);
            }
            return right;
        }
public Num countRPN(ArrayList<Object> right) {
            //
            Stacks aStack = new Stacks();
            Num op1, op2, result = null;
            String is = null;
            Iterator<Object> it = right.iterator();

            while (it.hasNext()) {
                Object ob = it.next();
                is = ob.toString();
                if (isOperator(is)) {
                    op2 =  (Num) aStack.pop();
                    op1 =  (Num) aStack.pop();
                    Num do_0 = twoResult(is, op1, op2);
                    if (do_0.getDenominator() == 0) {
                        return (new Num(-1, 1));
                    }
                    aStack.push(do_0);
                } else
                    aStack.push(ob);
            }
            result = (Num) aStack.pop();
            return result;
        }

  将其存入list,在出完题后check类进行扫描,对重复的题目进行汇报,但不予录入,若未满足题目数量需求情况下则继续循环

if (chk.checkRPN(question.toString(list)) && chk.checkanswer(result)) {
                ques.add(list);
                answer.add(result);
            }
public boolean checkRPN(String list) {
        if (check.size() == 0) {
            check.add(list);
            return true;
        } else {
            for (int i = 0; i < check.size(); i++) {
                if (check.get(i).equals(list)) {
                    // System.out.println("重复!" + (RPN++));
                    return false;
                }
            }
        }
        check.add(list);
        return true;
    }

  代码结构如下:

    Stacks-工具类

    Num-实体类(分数)

    NumOPHandle-随机数与随机运算符生成

    Ques-算数表达式生成

    QuesHandle-后缀表达式转换&计算

    Out/UI/Check-分别对应输出/显示/检查

  基础功能基本实现:

  选项1:根据输入的参数确定题目数量与值范围,输出txt,分别有答案,练习本,题目。

  选项2:在练习本对应序号填入答案后选择,会将结果显示。

  测试图:

  

  

  

  

  


 

个人小结:

  1.代码实现与需求分析过程中, 有如下参考

     http://www.cnblogs.com/edisonchou/p/4649954.html

  http://www.cnblogs.com/lanchaohao/p/7538431.html

     2.查重这一块基本没有自己的想法,一直跟着别人的思路走,无论是HashSet或者二叉树,在数据结构这一块的确薄弱,需要加强这方面的学习

  3.开发时严格意义上并没有采用敏捷开发模式,依旧有拍脑子敲键盘一撸到底的坏习惯。

  

附录:GitHub项目地址

 

 

 

 

 

 

 

 

 

posted @ 2018-03-31 18:46  符平居  阅读(227)  评论(0编辑  收藏  举报