标签:
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"; } } }
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; }
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