20162323周楠 “四则运算”第二周编程博客

20162323周楠 “四则运算”第二周编程博客

需求分析

实现一个命令行程序,要求:
自动生成小学四则运算题目(加、减、乘、除)
支持整数
支持多运算符(比如生成包含100个运算符的题目)
支持真分数
统计正确率

  • 自动生成一个四则运算题目,输入结果,回答完问题之后判断结果是否正确,再选择是否继续答题,以此循环。
  • 后续的可能拓展,可以支持多语言系统。
  • 除了整数以外,还要支持真分数的四则运算,真分数的运算,例如:1/6 + 1/8 = 7/24,并且要求能处理用户的输入,并判断对错,打分统计正确率。能处理用户输入的真分数。
  • 后续的可能拓展,可以订正错误答案
  • 后续的可能拓展,可以选择题目的难度等级

设计思路

这周的总体设计要在上周的基础上深化,上周我们的代码没有用到中缀表达式转后缀表达式,没有用到栈,所以这周不仅要对上一周的代码进行修改,而且还要在此基础上完成更深层的对真分数的要求。

实现四则运算中后缀转换类

实现四则运算后缀表达式计算类

实现四则运算真分数计算类

实现四则运算生成题目并判断正误

  • 题目生成

    • 可以独立使用
    • 可以选择生成的题目数量
  • 题目运算及正误判断

    • 用到中缀表达式转后缀表达式
    • 实现四则运算真分数的计算
    • 实现四则运算生成题目并判断正误
  • 支持多语言系统

  • 创建一个真分数类

    创建一个后缀表达式的计算类

    创建一个后缀表达式转中缀表达式的转换类

    题目生成并判断正误

    计算正确率

编写过程记录

PSP2.1 Personal Softwore Process Stage 预计耗时(分钟) 实际耗时(分钟) 重要成长
Planning 计划 20 30
Estimate 做这个任务需要多长时间 900 720
Development 开发 600 400
Analysis 需求分析(包括学习新技术) 60 40
Design Spec 生成设计文档 180 60
Design Review 设计复审(和同事审核设计软件) 300 100
Coding Standard 代码规范 (为目前的开发制定合适的规范) 60 60
Design 具体设计 300 240
Coding 具体编码 600 400
Code Review 代码复审 120 60
Test 测试(自我测试,修改代码,提交修改) 240 120
Reporting 报告 120 60
Test Report 测试报告 120 80
  | Size Measurement         |   计算工作量         | 20             |  20     |

| Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 | |

关键代码解释

  • 读入,输出文件需要用到的方法


  • 中缀转后缀,后缀计算思路
    • 中缀转后缀
public void evaluate(String expr) {
        String token;
        StringTokenizer tokenizer = new StringTokenizer(expr);

        while (tokenizer.hasMoreTokens()) {
            token = tokenizer.nextToken();

            if (token.equals("("))
                stack1.push(token);
            else if (token.equals("+") || token.equals("-")) {
                while (!stack1.empty()){
                    if(stack1.peek().equals("(")){
                        break;
                    }else list1.add(stack1.pop());
                }
                stack1.push(token);
            }else if (token.equals("*") || token.equals("/")) {
                if(!stack1.empty()) {
                    if (stack1.peek().equals("*") || stack1.peek().equals("/")) {
                        list1.add(stack1.pop());
                        stack1.push(token);
                    } else stack1.push(token);
                }else stack1.push(token);
            }
            else if (token.equals(")")) {
                while (!stack1.peek().equals("(")) {
                    list1.add(stack1.pop());
                }
                stack1.pop();
            }else list1.add(token);
        }
        while (!stack1.empty()) {
            list1.add(stack1.pop());
        }
        ListIterator<String > li = list1.listIterator();
        while (li.hasNext()) {
            Message += li.next() + " ";
            li.remove();
        }
        message = Message;
    }
  • 后缀表达式求值

 while (tokenizer.hasMoreTokens()) {
      token = tokenizer.nextToken();

      if (isOperator(token)) {
        op1 = stack.pop();
        op2 = stack.pop();

        StringTokenizer tokenizer1 = new StringTokenizer(op2, "/");
        numer1 = Integer.parseInt(tokenizer1.nextToken());
        if (tokenizer1.hasMoreTokens())
          denom1 = Integer.parseInt(tokenizer1.nextToken());
        else denom1 = 1;
        s1 = new RationalNumber(numer1,denom1);

        StringTokenizer tokenizer2 = new StringTokenizer(op1, "/");
        numer2 = Integer.parseInt(tokenizer2.nextToken());
        if (tokenizer2.hasMoreTokens())
          denom2 = Integer.parseInt(tokenizer2.nextToken());
        else denom2 = 1;
        s2 = new RationalNumber(numer2,denom2);

        computingresult = CalculateOp(token.charAt(0),s1,s2);
        stack.push(computingresult.toString());
      }else
        stack.push(token);
    }
    result = stack.pop();
    return result;
  }

  //符号匹配方法
  private boolean isOperator (String token){
    return ( token.equals("+") || token.equals("-") ||
            token.equals("*") || token.equals("/") );
  }

  //具体计算类。
  private RationalNumber CalculateOp(char operation, RationalNumber op1, RationalNumber op2)
  {
    RationalNumber result = null;
    switch (operation)
    {
      case ADD:
        result = op1.add(op2);
        break;
      case SUBTRACT:
        result = op1.subtract(op2);
        break;
      case MULTIPLY:
        result = op1.multiply(op2);
        break;
      case DIVIDE:
        result = op1.divide(op2);
        break;
    }
    return result;
  }

运行过程截图


代码托管地址

结对编程(https://git.oschina.net/zyl905487045/20162322-2323.git)

需要解释一下,我的IDEA出现了一点问题,没有办法git,所以由我的结对伙伴娅霖来进行git

实验过程中遇到的问题及解决思路

  • 问题1.中缀表达式转后缀表达式,加减比较容易转换,在乘除这块会涉及到优先级的问题,比较复杂,这块有一些问题

  • 问题1解决方案:之前娄老师在课上讲过这一块,再次把上课的PPT翻出来研究,而且里面所涉及到的不懂的部分在网上查找,分块解决,把大的问题解决了再解决小的问题,一步步细化,而且经过可以训练之后,会理解中后缀表达式的转化,这样来写,就会变得有思路,有迹可循。


  • 问题2.不知道怎么写入文件

  • 问题2解决方案:这个就需要java中的I/O流来对文件进行读写。java文件输出流是一种用于处理原始二进制数据的字节流类。为了将数据写入到文件中,必须将数据转换为字节,并保存到文件。

  • 问题3.不知道如何支持多语言系统

  • 问题3解决方案:实际上这里就是通过读取不同的配置文件获取不同的语言对应的字符,但是这样不会弄。所以就改变了思路,因为是比较简单的英文和繁体,所以就用选择语句,虽然这样在大的数据面前不太实用,但目前只能做到这样,会继续学习改进的。

评价

  • 结对编程中的两个角色
  • 领航员:20162322朱娅霖
  • 驾驶员:20162323周楠

我的结对小伙伴是20162322朱娅霖同学,这周我们的任务首先是把上周的代码进行修改完善,在此基础上进行对真分数的运算这部分的代码编写,,增加支持多语言系统,经过这两周的结对编程学习,我发现平均下来,结对编程时间花销比单人编程增加不少时间,但也会比单人编程减少不少的代码BUG。如果再算上后期代码的维护,结对编程比单人编程更有效率,还更加节省成本。有效地避免了闭门造车,并可以减少后期的code review(代码复审)时间,在Design Review(设计复审)会节约时间成本,可是还有一些没有做得好的地方是我们对任务的划分不够细致,还有两个人在一起结对学习可能会出现工作精力不能集中的情况。可能会交谈一些与工作无关的事情,反而分散注意力,导致效率比单人更为低下。但这样的情况还是很少的,我们会单独查资料然后一起学习,这样从两个角度可以看到更多的方面。

posted on 2017-05-21 23:15  GiggleKV  阅读(312)  评论(2)    收藏  举报

导航