第二次作业
git地址
https://github.com/JPL1988
git用户名
JPL1988
学号后5位
62131
博客链接
https://www.cnblogs.com/l123456l/p/10593365.html
作业链接
https://edu.cnblogs.com/campus/xnsy/SoftwareEngineeringClass1/homework/2793
Part 0. 背景
阿超家里的孩子上小学一年级了,这个暑假老师给家长们布置了一个作业:家长每天要给孩子出一些合理的,但要有些难度的四则运算题目,并且家长要对孩子的作业打分记录。
作为程序员的阿超心想,既然每天都需要出题,那何不做一个可以自动生成小学四则运算题目与解决题目的命令行 “软件”呢。他把老师的话翻译一下,就形成了这个软件的需求:
- 程序接收一个命令行参数 n,然后随机产生
n
道加减乘除(分别使用符号+-*/
来表示)练习题,每个数字在0
和100
之间,运算符在2
个 到3
个之间。 - 由于阿超的孩子才上一年级,并不知道分数。所以软件所出的练习题在运算过程中不得出现非整数,比如不能出现
3÷5+2=2.6
这样的算式。 - 练习题生成好后,将生成的
n
道练习题及其对应的正确答案输出到一个文件subject.txt
中。 当程序接收的参数为4时,以下为一个输出文件示例。
13+17-1=29
11*15-5=160
3+10+4-16=1
15÷5+3-2=4
这次阿超选择使用他最拿手的 C++
语言来完成这样的需求,工欲善其事必先利其器,第一步就需要先安装一个好用的 IDE ,在这里我们推荐使用 Visual Studio 2017
。
代码设计思路
1.我通过random产生随机数和计算符,把每一个符号和数字存入字符串数组
2,把中缀表达式转为后缀表达式
3,,计算每个子表达式的值,若为负数或小数,删去整个表达式,重新取值。
程序代码
using System;using System.Collections.Generic;using System.Text;namespace ConsoleApp1{
class wuyu {
publicstaticvoid Main(string[] args) {
Program program
= new Program(); program.Calculation(
10000000); }
}
publicclass Program {
StringBuilder lastresult
= new StringBuilder(); caculator caculators
= new caculator();private Random random = new Random();publicvoid Calculation(int n) {
for (int i = 0; i < n; i++) {
int sign = random.Next(2, 3); if (sign == 2) Calculation2();
else Calculation3();
}
System.IO.File.WriteAllText(
"D://homework.txt",lastresult.ToString(),Encoding.Default); }
privatevoid Calculation3() {
string[] s = newstring[5];int d = random.Next(1, 101);char z = getchar(); StringBuilder str
= two(s); str.Append(z);
str.Append(d);
int result = caculators.compute(s);if (result == -1) Calculation3();
else {
str.Append(
'='); str.Append(result);
str.Append(
''); lastresult.Append(str);
}
}
publicvoid Calculation2() {
string[] s = newstring[5]; StringBuilder str
= two(s);int result =caculators.compute(s);if (result == -1) Calculation2();
else {
str.Append(
'='); str.Append(result);
str.Append(
''); lastresult.Append(str);
}
}
privatechar getchar() {
Char res
= '+';int x = random.Next(0, 4);switch (x) {
case1:break;case2: res
= '-';break;case3: res
= '*';break;default: res
= '/';break; }
return res; }
public StringBuilder two(string[] strings) {
int a = random.Next(1, 101);int b = random.Next(1, 101);int c = random.Next(1, 101);char x = getchar();char y = getchar(); StringBuilder str
= new StringBuilder(); strings[
0] = a.ToString(); strings[
1] = x.ToString(); strings[
2] = b.ToString(); strings[
3] = y.ToString(); strings[
4] = c.ToString(); str.Append(a);
str.Append(x);
str.Append(b);
str.Append(y);
str.Append(c);
return str; }
}
publicclass caculator {
privatestaticstring Operator = "+-*/"; Queue
<string> postfix;//队列储存后缀表达式 Stack<string> stack;//栈储存计算后缀表达式时的数字
publicint compute(string[] s)
{
convert(s);//计算后缀表达式
stack = new Stack<string>(7);
int symbol;
int length = postfix.Count;
for (int i = 0; i < length; i++)
{
symbol = isOperator(postfix.Peek());
if (symbol > -1)//是否为操作符
{
postfix.Dequeue();//把操作符从队列里面移除
int d2 = int.Parse(stack.Pop());
int d1 = int.Parse(stack.Pop());//取出数据进行计算
int d3 = 0;
switch (symbol)
{
case0:
d3 = d1 + d2;
break;
case1://排除负数结果
d3 = d1 - d2;
if (d3 < 0)
return -1;
break;
case2:
d3 = d1 * d2;
break;
case3://排除小数结果
d3 = d1 / d2;
if (d3 * d2 != d1)
return -1;
break;
}
stack.Push(d3.ToString());//将计算结果压入数字栈
}
else
{
stack.Push(postfix.Dequeue());//将数字压入数字栈
}
}
returnint.Parse(stack.Pop());//返回最终结果
}
publicvoid convert(string[] strings)
{
postfix = new Queue<string>(strings.Length);
stack = new Stack<string>(7);
for (int i = 0; i < strings.Length; i++)
{
String tempc = strings[i];
if (i % 2 == 1)//说明是操作符
{
if (stack.Count == 0)//栈为空则将数据直接压入计算符栈
{
stack.Push(tempc);
}
else
{//栈不为空则和栈顶符号的优先级比较,将比当前优先级高的符号移除,并加进后缀表达式
while (stack.Count != 0 && priority(tempc, stack.Peek()))
{
postfix.Enqueue(stack.Pop());
}
stack.Push(tempc);//将当前符号压入栈顶
}
}
else
{
postfix.Enqueue(tempc);//若是数字则直接加进后缀表达式
}
}
while (stack.Count > 0)
{
postfix.Enqueue(stack.Pop());//将剩余操作符加进后缀表达式
}
}
publicint isOperator(string c)
{
return Operator.IndexOf(c);
}
publicbool priority(String o1, String o2)
{
return getPriority(o1) <= getPriority(o2);
}
publicint getPriority(String c)
{
switch (c)
{
case"+":
case"-":
return1;
default:
return2;
}
}
}
}
Part 1. 配置环境
最开始安装成了企业版,然后有个插件安装失败,也不能使用,重装几次的时候发现装错了版本。
Part 2. 克隆项目
拷贝成功,我的用户名JPL1988
安装git,克隆到本地,最开始安装的Git的桌面版,然后重新装的bash版
part3,单元测试
在单元测验时,遇到了一个较大的问题,那就是被测试的类如果确实静态Main方法无法被测试,报确实静态Main方法错误,但是由于之前做Java测试不需要Main方法。最后发现他人博客里的测试都要一个空类和空的Main方法,然后才测试成功。只是还不明白为什么,也没有查到。
单元测试运行
单元测试代码
using System;using Microsoft.VisualStudio.TestTools.UnitTesting;using ConsoleApp1;namespace UnitTestcalculator{
[TestClass]
publicclass UnitTest1 {
[TestMethod]
publicvoid TestMethod1() {
caculator ca
= new caculator();string[] s = newstring[] {"1","-","5","*","8" }; Assert.IsTrue(ca.compute(s)
==-1); }
[TestMethod]
publicvoid TestMethod2() {
caculator ca
= new caculator();string[] s = newstring[] { "1", "+", "5", "*", "8" }; Assert.IsTrue(ca.compute(s)
== 41); }
[TestMethod]
publicvoid TestMethod3() {
caculator ca
= new caculator();string[] s = newstring[] { "1", "/", "5", "*", "8" }; Assert.IsTrue(ca.compute(s)
== -1); }
[TestMethod]
publicvoid TestMethod4() {
caculator ca
= new caculator();string[] s = newstring[] { "5", "/", "1", "*", "8" }; Assert.IsTrue(ca.compute(s)
== 40); }
[TestMethod]
publicvoid TestMethod5() {
caculator ca
= new caculator();string[] s = newstring[] { "1", "*", "5", "+", "8" }; Assert.IsTrue(ca.compute(s)
== 13); }
}
}
part4回归测试
回归测试我是和断点调试一起使用的,纠正了求值过程中的很多错误结果和判断。
part5,断点调试
在编写后缀表达式计算过程中多次使用了,断点调试,添加监视,由于对后缀表达式不熟悉,在进行运算后,没有吧运算符出队列。仔细琢磨了很久。
part6效能测试
根据效能分析可知,string.indexof,和int32.tostring花费时间较长。可以优化,其实可以考虑有switch代替indexof.
part7,上传github
在第一次上传时,安装git add [D:\file]的提交方式出现错误,不需要加中括号。
git提交时要把厂库里的所有更新文件都进行git add和git commit 否则在进行git status 验证时不会通过
git push成功
提交成功
part8. 感想
由于之前做个Java单元测试,所以本次对于c#做单元测试中,被测试类需要一个main方法,不是很理解,我一直以为单元测试的地方就是程序入口。其次,github的使用不是很熟悉,项目由于我是在本地测试的所以没有在修改后就提交到git。本次实验我学会了后缀表达式求值,熟悉了对队列和栈的使用。
以上是 第二次作业 的全部内容, 来源链接: utcz.com/z/508859.html