2016012070小学四则运算练习软件项目报告

源码地址:https://git.coding.net/beijl695/EGener.git           (代码原创,仅供参考)

在课堂上写完一个四则运算出题小程序只完成了两个数的四则运算出题,这次又在那个小程序的基础上进行了拓展。

项目名称:EGener

用Java编写的四则运算等式生成器(包括分数等式,带括号等式和不带括号等式)
用法:
  java Main amount [-option]
  如java Main 50 -n
参数说明:
  参数一:
    amount 为数量1~1000
  参数二:
    默认不带参数:分数等式,带括号等式和不带括号等式循环生成
    -n:生成不带括号的整数等式
    -b:生成带括号的整数等式
    -f:分数等式

回顾开发流程

一、需求分析:

   1、根据输入参数,随机产生参数数目的四则运算等式;

   2、运算符3到5个,运算数范围(0~100),运算过程和结果不含小数和负数;

   3、实现带括号的等式生成,括号大于两个;

   4、实现分式等式的生成,运算过程和结果只能是真分数,不能出现负数;

   5、将2016012070和生成的等式输出到./result.txt中。

二、功能设计:

  1、如上面程序用法所示,可随机生成指定数目的等式的混合(包括分数等式,带括号等式和不带括号等式),可随机生成指定数目的指定等式。

  2、除了控制数目的参数,额外添加了一个控制生成等式类型的参数例如:Main 100 -n 表示生成100道带括号的整数等式。

三、设计实现:

程序的过程就是 输入 -> 处理 -> 输出(打印);

因为程序的功能需被拓展,所以要细化类,减少耦合。

下面是项目中的类名和功能

下面的主类代码已经清楚地展示生成器的作用。在Main方法中,等式生成器需要左式生成器进行初始化(左式生成器是等式生成器的组件),然后可通过等式生成器的next()方法生成等式。不同的左式生成器有不同的规则,但是接口都一样,所以都继承了LeftGenerator。

下面只展示了Main类的方法,这也是程序的总体构造,各个类代码请参见源码地址:https://git.coding.net/beijl695/EGener.git

import com.beijinlin.lib.*;
import java.io.*;

public class Main{
    public static void main(String[] args){
        int num = 0;
        //初始化不带括号的等式生成器
        EquationGenerator equaGen =
            new EquationGenerator(new LeftGenerator());

        //初始化带括号的等式生成器
        EquationGenerator equaGenwithBracket =
            new EquationGenerator(new LeftGeneratorWithBracket());

        //初始化分数的等式生成器
        FractionalEquationGenerator fequaGen =
            new FractionalEquationGenerator(new LeftGeneratorWithFraction());
System.out.println(equaGen.next());
System.out.println(equaGenwithBracket.next());
System.out.println(fequaGen.next());

 四、算法详解:

  程序中涉及到的主要是调度场算法,先将中缀表达式转化为后缀表达式,再进行计算。

此算法实现再等式生成器中,在此之前已经通过左式生成器生成了左式。

1,处理左式,实现运算数和运算符的分离,并存入队列1中。

2,设置一个栈用来存放符号,设置一个队列2用来存放后缀结果。

3,遍历队列1,如果是数字,直接加入队列2;如果是符号,左括号,乘号, 除号的话,直接入栈;如果是加号,减号的话,若栈为空,则可直接入栈。对于其他情况,先将栈弹出并加入队列2,直至栈顶为左括号或栈为空。注意的是,括号不入队列2。

4,当遍历完队列1,将符号栈中所有元素弹出,并加入队列2。

说的有些抽象。具体请参考:https://blog.csdn.net/acm_jl/article/details/51031005

五、测试运行:

 若输入参数有误,则提示消息如下:

下面是正常测试图,分数等式,带括号等式和不带括号等式循环生成,共十道

以下是带有附加参数二的命令

如下图,命令执行后生成单一的不带括号的整数等式,共20道。

 如下图,命令执行后生成单一的带括号的整数等式,共20道。

下面是分数等式的生成

经过大量地运行测试,发现了许多问题,如程序异常或逻辑问题导致结果不对,都一一解决,但可能还是存在没有检测到的问题。

该程序没有设置集合容器进行去重,运算数和运算符都是随机产生,有小概率产生重题。

目前产生的带括号的左式存在局限性。

 六、代码展示:

以下是将中缀表达式转换为后缀表达式的代码:

    //将中缀表达式转化为后缀表达式
    LinkedList<String> change(String s){
        //队列:未处理
        LinkedList<String> left = new LinkedList<String>();
        //栈:符号
        LinkedList<String> operators = new LinkedList<String>();
        //队列:结果
        LinkedList<String> result = new LinkedList<String>();

        //使用正则分析字符串并储存到未处理的队列
        Pattern p = Pattern.compile("\d+|[\+\-\*÷()]");
        Matcher m = p.matcher(s);
        String temp, top;
        while(m.find()){
            left.add(m.group());
        }
        while((temp = left.pollFirst()) != null){
            Pattern number = Pattern.compile("\d+");
            //如果是数字,直接加入结果队列
            if(number.matcher(temp).matches()){
                result.add(temp);
            }
            //判断符号入栈和出栈的条件
            else{
                if("*".equals(temp) || "÷".equals(temp) ||"(".equals(temp)||
                    ("+".equals(temp)||"-".equals(temp))&&
                    (operators.size()==0||"(".equals(operators.getLast()))){
                    operators.add(temp);
                }

                else if(")".equals(temp)){                                              //如果遇到右括号,弹出直至左括号
                    while(!(top = operators.pollLast()).equals("(")){
                            result.add(top);
                    }
                }

                else{                                                                    //遇到优先级低于或等于栈顶的符号,
                    while((top = operators.pollLast()) != null){                         //先弹出栈中符号,再将符号压入栈
                        if(!top.equals("(")){
                            result.add(top);
                        }
                        else{
                            operators.add("(");
                        }
                    }
                    operators.add(temp);
                }
            }
        }
        //当未处理的队列为空,将栈中所有符号弹出并入结果队列
        while((top = operators.pollLast()) != null){                                   //最后将栈全部弹出
            result.add(top);
        }
        return result;
    }

七、总结:

1、该程序为了实现可拓展性,我设计了左式生成器和等式生成器,做到细化类。每个类具备的功能是独立而足够的,既不臃肿,也不缺乏。等式生成器是该程序的核心类,功能就是生成等式,而左式生成器是等式生成器的组件。

2、程序虽然满足了需求,但还存在许多不足之处,如没有彻底去重,括号的产生有局限性。

3、为了使程序容易拓展,我在编码前做了一定的设计,因为我不想用java来写C程序,这也使我能够在编码上花更少的时间。

八、PSP展示:

PSP2.1

任务内容

计划共完成需要的时间(min)

实际完成需要的时间(min)

Planning

计划

10

30

·        Estimate

·   估计这个任务需要多少时间,并规划大致工作步骤

10

30

Development

开发

60 * 8

60 * 6

·        Analysis

·         需求分析 (包括学习新技术)

60

15

·        Design Spec

·         生成设计文档

30

60

·        Design Review

·         设计复审 (和同事审核设计文档)

0

0

·        Coding Standard

·         代码规范 (为目前的开发制定合适的规范)

0

0

·        Design

·         具体设计

30

60

·        Coding

·         具体编码

60 * 3

60 * 5

·        Code Review

·         代码复审

30

60

·        Test

·         测试(自我测试,修改代码,提交修改)

60

60 * 2

Reporting

报告

10

15

·         Test Report

·         测试报告

10

5

·         Size Measurement

·         计算工作量

2

5

·         Postmortem & Process Improvement Plan

·         事后总结, 并提出过程改进计划

4

5

原文地址:https://www.cnblogs.com/gongsunaokong/p/8643996.html