码迷,mamicode.com
首页 > 其他好文 > 详细

个人项目——四则运算题目生成程序

时间:2015-09-29 01:12:54      阅读:1478      评论:0      收藏:0      [点我收藏+]

标签:

任务:实现一个自动生成小学四则运算题目的命令行程序


 

1)PSP表格记录

PSP2.1

Personal Software Process Stages

估计

实际

Planning

计划

 

 

  · Estimate

  · 估计这个任务需要多少时间

 21h

 29h

Development

开发

 

 

  · Analysis

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

 1h

3h

  · Design Spec

  · 生成设计文档

 0.5h

0.5

  · Design Review

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

 0

0

  · Coding Standard

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

 0

0

  · Design

  · 具体设计

 1h

1h

  · Coding

  · 具体编码

 15h

20h

  · Code Review

  · 代码复审

 0

0

  · Test

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

 2h

3h

Reporting

报告

 

 

  · Test Report

  · 测试报告

 0.5h

0.5h

  · Size Measurement

  · 计算工作量

 0.5h

0.5h

  · Postmortem & Process Improvement Plan

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

 0.5h

0.5h

 

合计

 21h

29h

 

2)编码过程(主要是编码过程中遇到的问题所做的处理)

    1.  对带分数的表达式的处理。

    查阅相关资料时发现可以使用逆波兰表达式来处理数学表达式。其原理是将人们习惯的的中缀表达式转化成后缀表达式。查阅了相关代码,并在此基础上修改成可以支持分数的函数。其主要思想就是将一个整数化成n/1的形式,再进行相关的计算。我设计了如下的一个类:

技术分享
public class Fraction
    {
        private bool fraction;
        private Int64  child, parent;

        public bool Fract
        {
            get { return fraction; }
            set { fraction = value; }
        }

        public Int64 Parent
        {
            get { return parent; }
            set { parent = value; }
        }

        public Int64 Child
        {
            get { return child; }
            set { child = value; }
        }

        public static Fraction Parse(String str)
        {
            Fraction a = new Fraction();
            a.child = Int64.Parse(str);
            a.parent = 1;
            a.fraction = false;
            return a;
        }

        public static bool IsPositive(String a)
        {
            if (a.Contains("/") && a.Substring(0,1)!="-")
                return true;
            else if (Convert.ToInt64(a) > 0 && !a.Contains("/"))
                return true;
            else
                return false;
        }


        public static string ToString(Fraction fraction)
        {
            try
            {
                if (fraction.parent < 0)
                {
                    throw new Exception();
                }

                if (fraction.child == 0)
                {
                    return "0";
                }
                else if (fraction.fraction == true && fraction.child < fraction.parent)
                {
                    return Convert.ToString(fraction.child) + "/" + Convert.ToString(fraction.parent);
                }
                else if (fraction.fraction == true && fraction.child == fraction.parent)
                {
                    return "1";
                }
                else if (fraction.fraction == true && fraction.child > fraction.parent)
                {
                    Int64 i = fraction.child/fraction.parent;
                    Int64 j = fraction.child % fraction.parent;
                    if (j==0)
                    {
                        return Convert.ToString(i);
                    }
                    else
                        return Convert.ToString(i) + "" + Convert.ToString(j) + "/" + Convert.ToString(fraction.parent);
                }
                else
                    return Convert.ToString(fraction.child);
            }
            catch (Exception e)
            {
                return "-1";
            }
        }
    
    }
View Code

 

    2.  快速生成不相同的随机数

           因为程序要求可以生成一万个代码,在要求效率的基础上,肯定不能用简单的使用当前系统时间作为随机数的种子。否则在短时间内会生成大量一样的随机数。也不能用Sleep的方式,否则会降低程序的效率。查阅相关资料,问题得以解决。

    3.  产生不重复的表达式

           因为老师对需求做了些简化,我便想到了一个比较投机的办法。就是将中缀表达式化成后缀表达式,只要一个加号和乘号之前的两个数字位置进行调换,并存入表中,再用Contains的方法进行判断。

        举个例子:

           对于1+2+3的中缀形式,可以化为1 2 + 3 +的后缀形式,只要将1和2调换一个位置,变为2 1 + 3 + 只要以后的生成表达式和上面俩个式子不同,就不会有重复。

    同理的对于1+(2+3)的中缀形式是1 2 3 + +。调换后为1 3 2 + +。

        代码如下:

技术分享
public bool check(String Expression)
        {
           Calculator checknum = new Calculator();
           Queue<object> tempQueue = new Queue<object>();
           List<String> tempList = new List<string>();
           String str = "";
           String tempstr = "";
           tempQueue = checknum.PreOrderToPostOrder(Expression);
           while (tempQueue.Count > 0)
           {
               str = str + Convert.ToString(tempQueue.Peek()) + ",";
               tempList.Add(Convert.ToString(tempQueue.Dequeue()));
           }
           if ((tempList[2] == "+") || (tempList[2] == "×"))
           {
               String temp = tempList[0];
               tempList[0] = tempList[1];
               tempList[1] = temp;
               tempstr = tempList[0] + "," + tempList[1] + "," + tempList[2] + "," + tempList[3] + "," + tempList[4] + "," ;
           }
           else
           {
               String temp = tempList[1];
               tempList[1] = tempList[2];
               tempList[2] = temp;
               tempstr = tempList[0] + "," + tempList[1] + "," + tempList[2] + "," + tempList[3] + "," + tempList[4] + ","  ;
           }
           if (!postOrderList1.Contains(str)&&!postOrderList2.Contains(str))
           {
               postOrderList1.Enqueue(str);
               postOrderList2.Enqueue(tempstr);
               return true;
           }
           else
               return false;
       }
View Code

 

           

3)程序优化

对于生成10000个算式,没优化是这样的:

 技术分享

技术分享

没错,程序将近执行了3分钟....

其中可以看出Simplification这个函数占用的时间最长。这个函数是用来将一个分数化简成最简形式。一开始的思路是从分子逐个向下做减一的循环。当分子和分母同时可以将这个数整除,即为最大公约数。最后同时除以这个公约数即为最简形式。

后来发现可以使用辗转相除法化来找公约数,来提高整个程序的效率,相对应的getChild函数也不会调用那么多次的。

同理在ToString函数中会将一个假分数化成真分数,一开始也是用循环累加的方式。后来发现其系数可以是原分子除以分母的结果,分子可以是原分子对分母的求余。遂改进。

 

技术分享

 技术分享

这就是优化过后的结果。可以发现程序的效率大大的提升了。

 

4)测试

输入-n 10000 -r 10000 测试是否能生成一万个算式。

 技术分享

技术分享

 

输入-e -a 测试是否能判断自动生成的文件

技术分享

  

对文件进行修改,判断是否能正确判断正误。

将9988号题目的结果改为1。将9999的结果直接删除。

技术分享技术分享

程序均能正确判断。

并且经过人工肉眼扫描是否有假分数和负数的结果,和包含假分数的算术。均为扫描到。

 

5)个人感想

    对于这个项目,我个人感觉还是有些难度的。一开始对C#不是很熟悉,但是由于上学期面向对象课程对JAVA有了一个不错的了解,很快就上手了C#。

    整个项目做下来收获还是很丰富的,特别是逆波兰表达式的那一部分,对数据结构又有了更深的认识。其次是将上学期面向对象的编程习惯保持了下来。看来上学期的课程还是十分有作用的。

    然后就是,个人认为花了这么多时间在这个项目上,一个是对语言的不熟悉,另一个就是没有做好设计。一开始是就简单的把需求分为了3个部分:处理数学表达式、判断表达式及其答案是否匹配、随机生成不重复的表达式。但实际动手去做的过程中,遇到了各式各样的问题。除了在前面提到的比较重要的问题外,还遇到了例如TXT文件编码的问题,处理10000的数学表达式,int型是不够的,要改为Int64型才可以。

    在做的过程中还发现了string和String是等价的,而前者编译器在处理的时候会将其变成后者,然后再进行下一步的处理这些比较有意思的细节。

    最后:唯有自己动手去做,才能进一步的提高。

个人项目——四则运算题目生成程序

标签:

原文地址:http://www.cnblogs.com/Tanc-ANT/p/4845360.html

(0)
(1)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!