作业具体要求点 这里

Core组要求:

1.Calc()

这个Calc 函数接受字符串的输入(字符串里就是算术表达式,例如 “5*3.5”,“7/8 - 3/8 ”,“3 + 90 * 0.3”等等),这个模块的返回值是一个字符串。

2.Setting()

在生成四则运算题目之前,需要对一系列属性进行设置,例如生成题目的数量,操作数的数量,题目中操作数的数值的范围,运算符的种类,(+-*/,是否支持真分数运算,是否支持小数运算,是否支持乘方运算……

注:

题目中操作数的数值范围对于真分数来说是指其分母的范围,运算结果可以超出指定范围

当题目中包含小数时,答案亦以小数形式给出,结果为无限小数时保留小数点后两位

乘方运算的幂次方为小于5的自然数

3.Generate()

进行一些设置之后,就可以开始生成所需要的题目了,题目增加以下限制

  • 生成的题目计算过程中不能产生负数

  例如1 - 2 + 3 =,3 + (4 - 5) =,因为计算过程中产生了负数,都是无效的题目

  • 生成的题目中不能包括不必要的括号

  例如 1 + (2 * 3),(1 + 2)+ 3

  其中括号为不必要的括号,不能生产此类题目

  • 程序一次运行生成的题目不能重复

  即任何两道题目不能通过有限次交换+和×左右的算术表达式变换为同一道题目。例如,23 + 45 = 和45 + 23 = 是重复的题目,6 × 8 = 和8 × 6 = 也是重复的题目。3+(2+1)和1+2+3这两个题目是重复的,由于+是左结合的,1+2+3等价于(1+2)+3,也就是3+(1+2),也就是3+(2+1)。但是1+2+3和3+2+1是不重复的两道题,因为1+2+3等价于(1+2)+3,而3+2+1等价于(3+2)+1,它们之间不能通过有限次交换变成同一个题目。

实现以上接口,编写API文档,供UI组使用(亦可自行增加功能)。

PSP表格:

一、需求分析

  ①考虑本次作业的主要功能是接受setting、生成表达式,具体的Calc运算函数其实和整体关系不大,优先设计Class和setting。经过商讨,我们决定将Class名定为QuestionCore类,其中设置供setting使用的九个变量:

1.生成问题数量(int)questionNum 初值:40

2.最多操作符数(int)maxOpNum 初值:6

3.算式中数字最小值(int)minData 初值:0

4.算式中数字最大值(int)maxData 初值:15

5.操作符字符串,包括“+-*/^”(string)ops 初值:“+-*/^”,支持乱序输入,根据输入的字符串中包含的运算符进行生成算式

6.是否开启分数运算(bool)fracFlag 初值:true

7.小数精度(int)precise 初值:2

8.题目文件路径 (string)QPath 初值:Questions.txt

9.答案文件路径 (string)APath 初值:Answers.txt

这九个变量足以控制实现作业中的各种要求。同时,设置vector<string>容器的变量来存储结果。相应地设置相关函数。

  ②考虑生成运算式的方式,想起学习数据结构时“栈”一章里便是将生成运算式作为例题,故重拾谭浩强,初步预定采用栈来生成运算式。后来在组里讨论交流了一下,发现树结构更适合多运算式的随机生成,于是决定以树结构存储、栈形式导出,实现随机生成运算式的功能。树的结点定义结构体,索性定成一个Class:questionNode,其中包含value值、左孩子lchild、右孩子rchild和判别是数字结点还是运算符结点的bool变量opsFlag。

  ③考虑Calc函数的具体功能,是要对一个输入的式子进行运算,返回string形式的结果。基础运算即不涉及分数的基础四则运算+乘方,通过atoi、to_string等函数不难做到,拆分到CalcNum、CalcStr两个函数中,分别对输入的数字、字符串求解。 追加功能要求支持分数运算,即需要通分、设置带分数等,故加入约分模块,辗转相除法求出最大公约数后进行约分,在Calc中实现。

  ④考虑封装和对接要求,应该着手学习将CPP封装为dll的方法,并且要及时发布、写好API文档,尽早对接、互相完善。由于接口定义模糊不清,可以预计各组的接口都会有所不同,应当早做准备。

  ⑤特殊之处:结对编程。需要收集一些结对编程的技巧和经验,合理分工,共同进步。

二、具体设计

  ①设计两个类:questionNode和questionCore,Node是树节点,如上所述;Core是主要变量和函数的类,包含setting所需的控制变量和实现各种功能的函数。

  ②Core类中包含树节点Node* questions和string容器Answer,分别负责生成树、存树、操作树与存储生成式子的答案。生成的式子由getQue函数配合对树的操作得到,保存在string 的容器finalQue中。这样我们就可以通过生成一定数目的式子分别将结果和表达式放入Answer和finalQue,达成功能。树的操作有各种结点遍历、检验、转换成string等。

  ③考虑计算优先级和括号问题。括号要加但不能乱加,我们商量后采用一个比较笨的办法:对每个由其他运算符和数字组建好的式子,先随机生成一定数量的成对括号,找位置往式子里填。填完后,对于无须加括号的,将括号成对删除。此处需要注意的是中途新增需求:乘方运算的右边必须是小于五的自然数,也就是说括号落位还要避免落在乘方后边。

  ④考虑筛选合格算式问题,由算式中各阶段运算非负,设计isPositive函数来判断是否每一阶段都不为负。设计函数判断两颗运算式树是否在本次作业的意义下等同。由于在树生成和转化时逐个判断算式合格过于繁琐,我们采用过量生成、取用合格算式的策略。若合格算式不够多,则再次生成补充。

  ⑤考虑对接问题,设计setting函数参数如上所述,设计getResultFile函数,直接将两个vector中的数据分别导出到客户输入的路径下设定的文件中。

三、具体编码

  整体文件由question.h、question.cpp、main.cpp组成。question.h中声明了类和各类函数;除了构造和析构函数外,其他函数的实现均在question.cpp中进行。main函数主要用于测试功能。代码分别如下。

question.h

头文件已添加预编译头,可编译为dll文件。

 #include "Core10.h"
//random a~b
int questionCore::random(int a, int b)
{
return (rand() % (b - a + )) + a;
} //is operator
bool questionCore::isOp(char ch)
{
auto it = find(ops.begin(), ops.end(), ch);
if (it == ops.end())
return false;
return true;
} //is num
bool questionCore::isNum(char ch)
{
if (ch >= ''&&ch <= '')
return true;
return false;
} //is decimal
bool questionCore::isDeci(string str)
{
for (int i = ; i < str.size(); i++)
{
if (str[i] == '.')
return true;
}
return false;
} //op's priority, higher means prior
int questionCore::priority(char op)
{
switch (op)
{
case '#':return -;
case '\0':return -;
case '(':return ;
case ')':return ;//avoid ( ) be put out
case '+':
case '-':return ;
case '*':
case '%':
case '|':
case '/':return ;
case '^':return ;
default:return ;
}
} // return (a op b)
double questionCore::CalcNum(double a, double b, char op)
{
switch (op)
{
case '+':return (a + b);
case '-':return (a - b);
case '*':return (a * b);
case '|':return a / b;
case '/':return a / b;
case '%':return (int)a % (int)b;
case '^':return pow(a, b);
default:return a;
}
} //return answer of que
double questionCore::CalcStr(string & que)
{//OPTR: ops' stack; OPEN: nums' stack
int posTmp = que.find("*-");
if (posTmp != -)
return ;
que.push_back('\0');
stack<char> OPTR; OPTR.push('#');
stack<double> OPEN;
char ch = 'c', chTmp;
double num1, num2;
int pos = ; while (ch != '\0' || OPTR.top() != '#')
{
if (ch != '\0') { ch = que[pos]; pos++; }
if (!isOp(ch) && ch != '\0')
{
if (ch == ' ') continue;
else numPush(OPEN, que, pos);
continue;
}
switch (ch)
{
case '(':OPTR.push(ch); break;
case ')':
chTmp = OPTR.top();
while (chTmp != '(')
{
if (OPEN.empty())
throw "wrong form";
num1 = OPEN.top(); OPEN.pop();
if (OPEN.empty())
throw "wrong form";
num2 = OPEN.top(); OPEN.pop();
OPEN.push(CalcNum(num2, num1, chTmp));
OPTR.pop();
chTmp = OPTR.top();
}
OPTR.pop();
break;
default:
chTmp = OPTR.top();
while (priority(chTmp) >= priority(ch))
{
OPTR.pop();
if (OPEN.empty())
throw "wrong form";
num1 = OPEN.top(); OPEN.pop();
if (OPEN.empty())
throw "wrong form";
num2 = OPEN.top(); OPEN.pop();
OPEN.push(CalcNum(num2, num1, chTmp));
chTmp = OPTR.top();
}
if (ch != '\0')OPTR.push(ch);
break;
}
}
return OPEN.top();
} //push que's nums into stackT
void questionCore::numPush(stack<double> & stackT, string que, int & pos)
{
string strT;
char ch;
while (!isOp(que[pos - ]) && que[pos - ] != '\0')
{
ch = que[pos - ];
strT.push_back(ch);
pos++;
}
pos--;
stackT.push(atof(strT.c_str()));
} //find max divisor
int questionCore::getDivisor(string str)
{
string numTmp;
int times = ;
int divisorTmp = ;
int strLen = str.size();
int backNum = ;
for (int i = ; i < strLen; i++)
{
if (str[i] == '|' || str[i] == '/')
{
if (str[i + ] == '(')
{
i++; while (i <= strLen)
{
if (str[i] == '(')backNum++;
if (str[i] == ')')backNum--;
if (str[i] == '|' || str[i] == '/')divisorTmp *= getDivisor(str.substr(i));
if (divisorTmp == || divisorTmp>maxRange || divisorTmp<)
return ; numTmp.push_back(str[i]);
if (backNum == )break;
i++;
}
}
else
{
while (isNum(str[i + ]) && i + <= strLen)
{
numTmp.push_back(str[i + ]);
i++;
} }
numTmp.insert(, , '(');
times *= int(CalcStr(numTmp.append(")*").append(to_string(int(divisorTmp)))));
if (times == || times>maxRange || times<)
return ;
numTmp.clear();
}
}
if (times == || times>maxRange || times<)
return ;
return times;
} //Euclidean algorithm, zhanzhuanxiangchufa
int questionCore::gcd(int a, int b)
{
if (b != )
return gcd(b, a % b);
else
return a;
} //judge if elems in question are positive
bool questionCore::isPositive(questionNode* root, double &res)
{
double res1 = , res2 = ;
bool flag1, flag2;
if (root == NULL) return false;
if (root->opsFlag == true)
{
flag1 = isPositive(root->lchild, res1);
flag2 = isPositive(root->rchild, res2);
res = CalcNum(res1, res2, char(root->value));
if (res < || res>maxRange)return false;
else return flag1 && flag2;
}
else
{
res = root->value;
return true;
}
} //generate tree from ques, if success return ture
bool questionCore::generateTree(vector<string> & ques)
{
vector<string> res; string que, numStr;
stack<char> OPTR;
stack<questionNode*> OPEN;
questionNode *node1, *node2, *tempNode; for (int i = ; i < ques.size(); i++)
{
que = ques[i];
que.push_back('\0');
OPTR.push('#'); char ch = 'c', chTmp;
int pos = ; while (ch != '\0' || OPTR.top() != '#')
{
if (ch != '\0')ch = que[pos++]; if (!isOp(ch) && ch != '\0')
{
if (ch == ' ') continue;
else
{
while (!isOp(que[pos - ]) && que[pos - ] != '\0')
{
numStr.push_back(que[pos - ]);
pos++;
}
pos--;
tempNode = new questionNode(atoi(numStr.c_str()), false);
OPEN.push(tempNode);
numStr.clear();
}
continue;
}
switch (ch)
{
case '(':OPTR.push(ch); break;
case ')':
chTmp = OPTR.top();
while (chTmp != '(')
{
node1 = OPEN.top(); OPEN.pop();
node2 = OPEN.top(); OPEN.pop();
tempNode = new questionNode(int(chTmp), true, node2, node1);
OPEN.push(tempNode);
OPTR.pop();
chTmp = OPTR.top();
}
OPTR.pop();
break;
default:
chTmp = OPTR.top();
while (priority(chTmp) >= priority(ch))
{
OPTR.pop();
node1 = OPEN.top(); OPEN.pop();
node2 = OPEN.top(); OPEN.pop();
tempNode = new questionNode(int(chTmp), true, node2, node1);
OPEN.push(tempNode);
chTmp = OPTR.top();
}
if (ch != '\0')OPTR.push(ch);
break;
}//switch
}//while
questions.push_back(OPEN.top());
OPEN.pop();
}
return true;
} //judge if 2 trees are the same
bool questionCore::isSame(questionNode* root1, questionNode* root2)
{
if (root1 == NULL && root2 == NULL)
return true;
else if (root1 == NULL || root2 == NULL)
return false; if (root2->value != root1->value)
return false;
else
return isSame(root1->rchild, root2->rchild) && isSame(root1->lchild, root2->lchild);
} //judge if 2 trees are equal
bool questionCore::isEqual(questionNode* root1, questionNode* root2)
{
if (root1 == NULL && root2 == NULL)
return true;
else if (root1 == NULL || root2 == NULL)
return false; bool eFlag1, eFlag2;
if (isSame(root1, root2))
return true;
else
{
eFlag1 = isEqual(root1->lchild, root2->lchild) && isEqual(root1->rchild, root2->rchild);
eFlag2 = isEqual(root1->rchild, root2->lchild) && isEqual(root1->lchild, root2->rchild);
return (eFlag1 || eFlag2) && (root1->value == root2->value);
}
} //judge if tree fit conditions
bool questionCore::judgeTree()
{
int rquesNum = questions.size(); for (int i = ; i < rquesNum; i++)
{
fitFlag[i] = isPositive(questions[i], result[i]);
for (int j = ; j < i; j++)
{
if (result[i] == result[j])
{
if (isEqual(questions[i], questions[j]))
{
fitFlag[i] = false;
isEqual(questions[i], questions[j]);
break;
}
}
}
}
return true;
} //generate questions
vector<string> questionCore::generateQue(int queNum)
{
vector<string> res;
string strTmp;
int num, chOp;
string numStr;
int leftParenPos, rightParenPos;
int opNum, parenNum;
bool isPow = false;
int powFlag = ; for (int i = ; i < queNum; i++)
{
opNum = random(, maxOpNum); for (int j = ; j < opNum; j++)
{
if (isPow == false)
{
num = random(minRange, range);
numStr = to_string(num);
}
else
{
num = random(, );
numStr = to_string(num);
isPow = false;
}
chOp = ops[random(, ops.size() - - powFlag)];
if (char(chOp) == '^')
{
isPow = true;
powFlag = ;
} strTmp.append(numStr);
strTmp.push_back(chOp);
}
num = random(minRange, range);
numStr = to_string(num);
strTmp.append(numStr); parenNum = random(, opNum); for (; parenNum>; parenNum--)
{
leftParenPos = random(, strTmp.size() - );
rightParenPos = random(leftParenPos + , strTmp.size()); while ((leftParenPos != && (!isNum(strTmp[leftParenPos]) || !isOp(strTmp[leftParenPos - ]))) || (leftParenPos != && strTmp[leftParenPos] == '^'))
{
leftParenPos--;
}
strTmp.insert(leftParenPos, , '('); while (rightParenPos != strTmp.size() && (!isNum(strTmp[rightParenPos - ]) || !isOp(strTmp[rightParenPos])))
{
rightParenPos++;
}
strTmp.insert(rightParenPos, , ')');
}
res.push_back(strTmp);
strTmp.clear();
powFlag = ;
}
return res;
} //transform tree to str
void questionCore::treeToStr(questionNode* root, string &pre)
{ if (root == NULL) return;
if (root->opsFlag == false)
{
pre.append(to_string(root->value));
return;
} if (root->lchild->opsFlag == false)
treeToStr(root->lchild, pre);
else if ((priority(root->value) > priority(root->lchild->value)) || (root->value == '^'))
{
pre.push_back('(');
treeToStr(root->lchild, pre);
pre.push_back(')');
}
else
treeToStr(root->lchild, pre); pre.push_back(char(root->value)); if (root->rchild->opsFlag == false)
treeToStr(root->rchild, pre);
else if ((priority(root->value) >= priority(root->rchild->value)) || (root->value == '^'))
{
pre.push_back('(');
treeToStr(root->rchild, pre);
pre.push_back(')');
}
else
treeToStr(root->rchild, pre); return;
} //transform original questions to formal questions
vector<string> questionCore::quesToStr(vector<questionNode*> Quess)
{
string strTmp;
string strExm;
vector<string> finishStr;
int count = ;
int rightNum = ;
bool flag = true;
int dot = ;
bool flag2 = true; for (int i = ; i < Quess.size(); i++)
{
treeToStr(Quess[i], strTmp);
for (int j = ; j<strTmp.size() - ; j++)
if (strTmp[j] == '^')
if ((strTmp[j + ] > '') || (strTmp[j + ] == '('))
{
flag = false; break;
}
if (!flag) {
strTmp.clear();
flag = true;
continue;
}
strExm = Calc(strTmp);
for (int j = ; j < strExm.size(); j++) {
if (strExm[j] == '\'') dot = j;
if (strExm[j] == '|')
if (j - dot > || strExm.size() - j > )
flag2 = false;
}
if (!flag2) {
strTmp.clear();
strExm.clear();
flag2 = true;
dot = ;
continue;
} finishStr.push_back(strTmp);
strTmp.clear();
count++;
if (count >= quesNum)
break;
}
return finishStr;
} //below:public function //free and reset
bool questionCore::Clear() {
int Num = questions.size();
for (int i = ; i < Num; i++)
{
questionNode* temp = questions[i];
deleteQues(temp);
}
questions.clear();
Answer.clear();
return true;
} //get real fraction and return result
string questionCore::Calc(string inQues)
{
int devisor;
int intNum;
string tpQues;
long res; if (fracFlag == true) {
devisor = getDivisor(inQues); if (fracFlag&&devisor > && devisor < maxRange && !isDeci(inQues))//get the real fraction
{
tpQues.append(to_string(devisor));
tpQues.append("*(");
tpQues.append(inQues).push_back(')');
res = int(CalcStr(tpQues));
intNum = gcd(res, devisor);
tpQues = to_string(int(res / intNum));
if (devisor / intNum != )
{
if (res > devisor)
{
tpQues.clear();
tpQues.append(to_string(int(res / devisor))).append("'").append(to_string(int(res / intNum - int(res / devisor)*(devisor / intNum)))).append("|").append(to_string(devisor / intNum));
}
else
tpQues.append("|").append(to_string(devisor / intNum));
}
return tpQues;
}
else
{
tpQues = to_string(CalcStr(inQues));
for (int i = ; i < - precise; i++)
tpQues.pop_back();
if (precise == )
tpQues.pop_back();
return tpQues;
}
}
//if not fraction
else {
tpQues = to_string(CalcStr(inQues));
for (int i = ; i < - precise; i++)//set precise
tpQues.pop_back();
if (precise == )
tpQues.pop_back();
return tpQues;
}
} //get questions
vector<string> questionCore::getQues() { vector<string> originQues;
vector<questionNode*> judgedQues;
vector<string> finalQues, tempQues; originQues = generateQue( * quesNum);
//generate 10 times questions and choose 1/10 from them
/*for (int i = 0; i < originQues.size()-1; i++) {
if (originQues[i].find("^("))
for (int j = i; j < originQues.size() - 2; j++)
originQues[j] = originQues[j + 1];
}*/
/*for (vector<string>::iterator it = originQues.begin();it != originQues.end();)
{
if ((*it).find("^("))
//删除指定元素,返回指向删除元素的下一个元素的位置的迭代器
it = originQues.erase(it);
else
//迭代器指向下一个元素位置
++it;
}*/ generateTree(originQues);
judgeTree();//build and judge for (int i = ; i < questions.size(); i++)
{
if (fitFlag[i] == true)
judgedQues.push_back(questions[i]);
} finalQues = quesToStr(judgedQues); for (int i = ; i < finalQues.size(); i++)
{
Answer.push_back(Calc(finalQues[i]));
} //add ' ' between ops and nums
string strTmp;
for (int i = ; i < finalQues.size(); i++)
{
strTmp = finalQues[i];
for (int j = ; j < strTmp.size(); j++)
{
if (strTmp[j] == '|'&&fracFlag == true) continue; else if (isOp(strTmp[j]) && strTmp[j] != '('&&strTmp[j] != ')')
{
strTmp.insert(j, , ' ');
strTmp.insert(j + , , ' ');
j += ;
}
}//for
finalQues[i] = strTmp;
}//for return finalQues;
} //get answers
vector<string> questionCore::getAns() {
return Answer;
} //setting
bool questionCore::setting(int queNum = , int maxOpnum = , int MinR = , int MaxR = , string op = "+-*/^", bool fraction = true, int preci = , string QPath = "Questions.txt", string APath = "Answers.txt")
{
quesNum = queNum;
maxOpNum = maxOpnum;
minRange = MinR;
range = MaxR;
ops.clear();
for (int i = ; i < op.size(); i++)
{
ops.push_back(op[i]);
}
fracFlag = fraction;
precise = preci;
QuePath = QPath;
AnsPath = APath;
setOps();
return true;
} //add ( ) into ops . if fraction, add function
void questionCore::setOps() {
if (fracFlag)
ops.insert(ops.end(), '|');
ops.insert(ops.end(), , '(');
ops.insert(ops.end(), , ')');
} //getResultFile, output Questions.txt , Answers.txt
void questionCore::getResultFile() {
vector<string> Ques = getQues();
vector<string> Ans = getAns(); ofstream foutQues;
foutQues.open(QuePath, ios::out);
for (int i = ; i < Ques.size(); i++) {
foutQues << Ques[i] << endl;
}
foutQues.close(); ofstream foutAns;
foutAns.open(AnsPath, ios::out);
for (int i = ; i < Ans.size(); i++) {
foutAns << Ans[i] << endl;
}
foutAns.close();
Clear();
}

question.cpp

 #include "question.h"
using namespace std; int main()
{
questionCore Work(); Work.setting(, , , , "+-*/^", true, );//num of questions, num of ops, min of nums, max of nums, ops(+-*/^), if need fraction, precise
// int int int int string bool int
Work.getResultFile(); return ;
}

main.cpp

函数前均已写明功能,实现过程并不算复杂,变量名调整得更易读了。

四、测试

  测试环节由我们2人分工,各自出样例导入setting,观察输出函数结果的情况。有一次结果中突然多了一些负数,我debug半天百思不得其解,队友却很快提醒我:我把CalNum函数中变量的先后顺序搞错了,运算数与被运算数换了位置。这让我节省了非常多的时间。经过重重磨难,我们相互督促、相互鼓励,终于将大部分功能基本完成,需要学习dll等待对接。cpp转dll可以说是我遇见过的最坑的博客问题群,各博主们都在教“一加一”,却没有一份教程详细告诉我们成型的cpp和h文件要怎么转换为dll。因此,我们又花费了大量时间摸索dll文件的制作,比其他组慢了一拍。最后,还是组里的一位同学给了我们帮助,让我们得以从繁琐蒙蔽的dll误导中走出来。今后有空,我要写一份真正有用的cpp转dll博客,不让这样的悲剧再发生。

  对接时,我们先找了组里的一队UI,面对面对接,但他的QT似乎有点问题,经过他一段时间的升级编译器后,我们总算有惊无险地对接成功。随后,我们将头文件、dll和lib文件和API文档保存在压缩文件中,发布到群里,目前它正在等待可爱善良帅气大方好心的UI组宠幸。

五、结对

  ①结对编程在这次作业中最直接的好处就是干的活少了,一起讨论、设计完函数后可以共同实现、轮班,相互测试,完成效率比较高。同时,由于一人编码、一人监督,bug率大大降低,有一次我的if函数中犯了个很低级的逻辑错误,立马就被队友机智地识破并指出,省去了巨大的debug时间开销。

  ②从这次结对中,我学到了敢于担当、积极进取的精神,学会了与他人一同合作、共同开发软件,也发现了自己知识层面的许多不足,需要继续努力。

  ③今后工作中若有机会,我会选择结对编程。

                              图为我帮队友同步审核代码

六、总结反思

  本次结对编程中的收获上文中也说得差不多了,补充一点:学到了dll的相关知识且打算抽空写一篇cpp转dll攻略。总的来说还有一些做得不够好的地方,比如接口的设计除了兼容文件输入、字符串输入外,还能更加人性化一点、增加更多功能方便UI组调用等等,但由于时间确实紧张,没能实现多少。

  对于这门课的看法,我认为这门课确实比较锻炼动手能力,但很多时候一些通知和需求下发得比较晚,任务也比较重,对我们的负担还是相当大的。在有个人作业、结对作业的周,我根本没有时间去碰我们的团队作业,还一定程度上影响了我正常的课业学习。但总体而言,我还是比较喜欢这门课的,希望以后的团队作业中,我们组能同心协力、共创佳绩。

现代软件工程HW2:结对编程-生成五则运算式-Core10组 [PB16110698+PB16120162]的更多相关文章

  1. BUAA软件工程_结对编程

    1.写在前面 项目 内容 所属课程 2020春季计算机学院软件工程(罗杰 任健) (北航) 作业要求 结对项目作业 课程目标 培养软件开发能力 本作业对实现目标的具体作用 培养结对编程开发项目的能力 ...

  2. 佛系结对编程---四则运算(Core 第四组)

    ----by core 第四组 ( 邹卫其 范力 ) 一. 项目介绍 1. 能自动生成小学四则运算题目并给出答案,生成题目时可以选择下列参数:   1)生成题目数量   2)每道题目中运算数数量   ...

  3. 结对编程收获-Core10组-PB16110698

    本周结对编程追加作业:记录收获.坦白说,我的收获多而杂,一时不知从何说起,以下试图从各方面简要谈谈. 一.编程能力收获 从编程能力方面,我收获的主要是类的设计思路和算法设计.在作业要求blog的指引下 ...

  4. 结对编程2—Fault&Error&Failure

    学习进度表 点滴成就 学习时间 新编写代码行数 博客量(篇) 学到知识点 第一周 8 0 0 了解软件工程 第二周 10 0 1 博文一篇 第三周 15 0 2 选择项目.调查问卷 第四周 20 80 ...

  5. PIE结对编程

    学习进度条 点滴成就 学习时间 新编写代码行数 博客量 学到知识点 第一周 8 0 0 了解软件工程 第二周 7 0 1 了解软件工程 第三周 11 0 1 用例图 第四周 6 25 0 结对编程 第 ...

  6. 11061160_11061151_Pair Project: Elevator Scheduler软件工程结对编程作业总结

    软件工程结对编程作业总结 11061160  顾泽鹏 11061151  庞梦劼 一.关于结对编程 这次的软工任务既不是单打独斗的个人任务,也不是集思广益的团队项目,而是人数为两人的结对编程.两个人合 ...

  7. 软件工程启程篇章:结对编程和进阶四则运算(197 & 199)

    0x01 :序言:无关的事 I wrote a sign called "Dead End" in front of myself, but love crossed it wit ...

  8. 软件工程结对编程-2017282110264&2017282110249

    0 小组成员 李世钰 / 2017202110264 王成科 / 2017282110249 1 项目 GitHub 地址 && 演示地址 GitHub: https://github ...

  9. 集大软件工程15级结对编程week1

    集大软件工程15级结对编程week1 0. 团队成员 姓名 学号 博客园首页 码云主页 孙志威 20152112307 Agt Eurekaaa 孙慧君 201521123098 野原泽君 野原泽君 ...

随机推荐

  1. XML 扩展部分

    引入命名空间 xmlns DTD缺点 1.不支持命名空间 2.支持的数据类型很少 3.DTD不可扩展 4.DTD不遵循XML规范 DTD的优点 简洁 schema 通过schema来解决DTD的不足 ...

  2. Flink 配置文件详解

    前面文章我们已经知道 Flink 是什么东西了,安装好 Flink 后,我们再来看下安装路径下的配置文件吧. 安装目录下主要有 flink-conf.yaml 配置.日志的配置文件.zk 配置.Fli ...

  3. Codeforcs 1183B Equalize Prices

    题目链接:codeforces.com/problemset/problem/1183/B 题意:给你 n 个数,每个数能在k范围内上下浮动,求能否使所有数相等,能输出相等的最大值,不能输出 -1. ...

  4. Git 学习第一天

    本文是根据廖雪峰老师的git教程记录的学习笔记,特此说明,原教程链接https://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c ...

  5. 剑指offer——53字符流中第一个只出现一次的字符

    题目描述 请实现一个函数用来找出字符流中第一个只出现一次的字符.例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g".当从该字符流中读出 ...

  6. Servlet.init() for servlet [springmvc] threw exception

    项目还没开始做,就碰到那么多问题.. 报错一:/oa/news/%E6%A0%8F%E7%9B%AE%E7%AE%A1%E7%90%86.jsp 1.一开始是jsp的页面名称为中文,改了 2.接着仍然 ...

  7. js进阶之路,关于UI资源的优化(转载)

    以下场景往往由于事件频繁被触发,因而频繁执行DOM操作.资源加载等重行为,导致UI停顿甚至浏览器崩溃. 1. window对象的resize.scroll事件 2. 拖拽时的mousemove事件 3 ...

  8. JS对象 编程练习 某班的成绩出来了,现在老师要把班级的成绩打印出来。 效果图: XXXX年XX月X日 星期X--班级总分为:81

    编程练习 某班的成绩出来了,现在老师要把班级的成绩打印出来. 效果图: XXXX年XX月X日 星期X--班级总分为:81 格式要求: 1.显示打印的日期. 格式为类似"XXXX年XX月XX日 ...

  9. Mybatis中$和#取数据的区别

    Mybatis配置中,取出map入参的数据一般有两种方式#{key}和${key},下面是这两种取值的区别: 以同样的语句做对比: <select id="geUserByParam1 ...

  10. c++11 std::move()

    简单点理解,c++11 中的std::move() 函数,实际上就是将一个左值强制转换成一个右值引用数据类型,从而可以调用相应的对右值引用重载的函数. 如果使用std::move() 的返回值做为参数 ...