----by core 第四组 ( 邹卫其 范力 )

一. 项目介绍

1. 能自动生成小学四则运算题目并给出答案,生成题目时可以选择下列参数:

   1)生成题目数量

   2)每道题目中运算数数量

   3)运算数数值范围

   4)运算符种类(  +  -  *  /  ^  )

   5)运算数类型(整数,小数,分数)

   6)运算数精度(保留到小数点后几位)

2. 将四则运算的计算功能包装在一个模块中( class 或 DLL)

3. 将 core 模块通过一定的 API 接口 (Application Programming Interface) 来和 UI 组对接

4. UI 组测试所有 core 组 DLL 后,core 组需根据 UI 组的测试结果进行反馈优化

5. 项目管理和撰写博客

6. 项目 Github 地址:https://github.com/eudaem/homework2/pull/2

二. 功能分析

1. 创建 class Node 类, 储存数据信息,所有操作数值以分数存储;以 Node 类为节点建立二叉树存储表达式所有信息。

2. 算术表达式树的树枝天然是运算符,树叶是操作数;先随机生成运算符树,再将树叶补全即可。

3. 在用户选择乘方时我们将 '^' 运算符沉到运算符树底,保证算术表达式不会过于复杂。

4. 对 Node 类重载加、减、乘、除、乘方运算,重载中所有运算均以分数运算完成。

5. 递归计算表达式树的值,递归检测到负数时交换左右子树,保证运算过程不出现负数。

6. 递归生成中缀表达式,并合理地加上括号,以 string 类存储。

7. 封装大类 Core,创建对象 cal,通过成员函数设置相关参数 , 生成的题目和答案以 string 串的形式传递。

 三. 代码实现

1. 定义 Core 类(封装成大类)

 class Core
{
private:
int que_num = ; //题目数量
int data_num = ; //操作数数量
int range = ; //计算的数值范围
int opr_type = ; //操作符种类 0.加减 1.加减乘 2.加减乘除 3.加减乘除乘方
int data_type = ; //0整数 1小数 2分数
int accuracy = ;
string* que = new string[que_num + ];
string* ans = new string[que_num + ];
public:
void set_que_num(int a) { que_num = a; }
void set_data_num(int a) { data_num = a; }
void set_range(int a) { range = a; }
void set_opr_type(int a) { opr_type = a; }
void set_data_type(int a) { data_type = a; }
void set_accuracy(int a) { accuracy = a; }
int get_que_num() { return que_num; }
int get_data_num() { return data_num; }
int get_range() { return range; }
int get_opr_type() { return opr_type; }
int get_data_type() { return data_type; }
int get_accuracy() { return accuracy; }
string *getQue();
string *getAns();
private:
string expstring(Node *root);
Node *creatOptree();
Node calc(Node *root);
void previsite(Node *head);
char operat();
char int_operat();
int get_factor(int a);
};

2. 设置类的参数并调用示例

 int main()
{
Core cal;
string *q, *a; cal.set_data_num();
cal.set_que_num();
cal.set_range();
cal.set_opr_type();
cal.set_data_type();
cal.set_accuracy(); q = cal.getQue();
a = cal.getAns();
for (int i = ; i <= cal.get_que_num(); i++)
{
cout << q[i] << " = " << a[i] << endl << endl;
} system("pause");
return ;
}

3. 定义节点 Node 类

 class Node
{
public:
Node() { top = -; bottom = -; operat = ; left = NULL; right = NULL; }
Node(int t, int b, char opr) { top = t; bottom = b; operat = opr; left = NULL; right = NULL; }
void simp();
int gcd(int p, int q);
Node operator + (Node n2);
Node operator - (Node n2);
Node operator * (Node n2);
Node operator / (Node n2);
Node operator ^ (Node n2);
Node operator = (Node n2); public:
int top;
int bottom;
char operat;
class Node *left;
class Node *right; }; Node Node::operator + (Node n2)
{
Node n;
n.top = top*n2.bottom + bottom*n2.top;
n.bottom = bottom*n2.bottom;
n.operat = ;
n.left = NULL;
n.right = NULL;
n.simp();
return n;
}
Node Node::operator - (Node n2)
{
Node n;
n.top = top*n2.bottom - bottom*n2.top;
n.bottom = bottom*n2.bottom;
n.operat = ;
n.left = NULL;
n.right = NULL;
n.simp();
return n;
}
Node Node::operator * (Node n2)
{
Node n;
n.top = top*n2.top;
n.bottom = bottom*n2.bottom;
n.operat = ;
n.left = NULL;
n.right = NULL;
n.simp();
return n;
}
Node Node::operator / (Node n2)
{
Node n;
n.top = top*n2.bottom;
n.bottom = bottom*n2.top;
n.operat = ;
n.left = NULL;
n.right = NULL;
n.simp();
return n;
}
Node Node::operator ^ (Node n2)
{
Node n;
n.top = (int)pow(top, n2.top);
n.bottom = (int)pow(bottom, n2.top);
n.operat = ;
n.left = NULL;
n.right = NULL;
n.simp(); return n;
}
Node Node::operator = (Node n2)
{
top = n2.top;
bottom = n2.bottom;
operat = n2.operat;
return Node(n2.top, n2.bottom, );
}

4. 随机生成一颗算数表达式树

 Node* Core::creatOptree()
{
Node *head = NULL, *p = NULL, *q = NULL;
int i = , j = ;
head = new Node;
head->operat = '+'; for (i = , j = ; i < data_num - ; i++)
{
p = head;
while (p)
{
if (rand() % ) {
if (p->left) p = p->left;
else {
q = new Node;
if (data_type == ) q->operat = int_operat();
else q->operat = operat();
p->left = q;
break;
}
}
else {
if (p->right) p = p->right;
else {
q = new Node;
if (data_type == ) q->operat = int_operat();
else q->operat = operat();
p->right = q;
break;
}
}
}//end while
}//end if
return head;
} void Core::previsite(Node *head)
{
if (!head) return;
class Node *q = NULL, *p = NULL;
if (head->operat && opr_type == && !head->left && !head->right)
{
int temp = ;
temp = rand() % ;
if (temp == ) head->operat = '^';
} if (head->operat && data_type == && (opr_type == || opr_type == ) && !head->left && !head->right)
{
int temp = ;
temp = rand() % ;
if (temp == ) head->operat = '/';
} if (head->operat && !head->left)
{
p = new Node;
//reset(q);
p->bottom = rand() % range + ;
p->top = rand() % range + ;
if (data_type == ) p->bottom = ; //整数
if (data_type == && head->operat == '/') p->top = rand() % range + ;
if (data_type == ) //小数
{
p->bottom = ;
p->top = rand() % ( * range);
}
if (head->operat == '^')
{
int min = (range < ) ? range : ;
p->bottom = ;
p->top = rand() % min + ;
}
head->left = p;
}
if (head->operat && !head->right)
{
q = new Node;
//reset(q);
q->bottom = rand() % range + ;
q->top = rand() % range + ;
if (data_type == ) q->bottom = ; //整数
if (data_type == && head->operat == '/') q->top = get_factor(head->left->top);
if (data_type == ) //小数
{
q->bottom = ;
q->top = rand() % ( * range);
}
if (head->operat == '^') //乘方
{
int min = (range <= ) ? range : ;
q->bottom = ;
q->top = rand() % min + ;
}
head->right = q;
}
previsite(head->left);
previsite(head->right); }

5. 计算表达式树数值 

 Node Core:: calc(Node *root)   //计算树的值
{
Node answer;
if (root == NULL)
return answer;
char opr = root->operat; if (opr == )
{
return *root;
}
else if (opr == '+')
{
return calc(root->left) + calc(root->right);
}
else if (opr == '-')
{
answer = (calc(root->left) - calc(root->right));
if (answer.top < )
{
Node *temp = root->left;
root->left = root->right;
root->right = temp;
answer.top *= -;
}
return answer;
}
else if (opr == '*')
{
return calc(root->left) * calc(root->right);
} else if (opr == '/')
{
if (data_type == )
{ }
return calc(root->left) / calc(root->right);
} else if (opr == '^')
{
return calc(root->left) ^ calc(root->right);
}
else
return answer;
}

6. 打印中缀表达式

 string Core::expstring(Node *root)  //生成中缀表达式  分子分母间用 |
{
if (root == NULL)
return que[];
if (root->left)
{
if ((root->left->operat == '+' || root->left->operat == '-') && (root->operat == '*' || root->operat == '/'))
{
que[] += "( ";
expstring(root->left);
que[] += ") ";
}
else if (root->operat == '^' && root->left->operat)
{
que[] += "( ";
expstring(root->left);
que[] += ") ";
}
else
expstring(root->left);
} if (root->operat == )
{
if (data_type == )
{
double t = 1.0 * root->top / root->bottom;
stringstream s1;
s1 << t;
que[] += s1.str();
que[] += " ";
}
else
{
stringstream s2;
s2 << root->top;
que[] += s2.str();
if (root->bottom > )
{
que[] += "|";
stringstream s3;
s3 << root->bottom;
que[] += s3.str();
}
que[] += " ";
}
}
else
{
que[] += root->operat;
que[] += " ";
} if (root->right)
{
if ((root->operat == '-' || root->operat == '*') && (root->right->operat == '-' || root->right->operat == '+'))
{
que[] += "( ";
expstring(root->right);
que[] += ") ";
}
else if (root->operat == '/' && (root->right->operat && root->right->operat != '^'))
{
que[] += "( ";
expstring(root->right);
que[] += ") ";
}
else if (root->operat == '^'&& root->right->operat)
{
que[] += "( ";
expstring(root->right);
que[] += ") ";
}
else
expstring(root->right);
}
return que[];
}

7. 生成题目 string 数组

 string* Core::getQue()
{
Node *head, result;
que = new string[que_num + ];
ans = new string[que_num + ];
for (int i = ; i <= que_num; i++)
{
head = creatOptree();
previsite(head);
result = calc(head);
result.simp();
if (result.bottom == || result.top < )
i--;
else
{
que[] = "";
que[i] = expstring(head);
if (data_type == )
{
double t = 1.0 * result.top / result.bottom;
stringstream s1;
s1 << t;
ans[i] += s1.str();
}
else
{
stringstream s2;
s2 << result.top;
ans[i] += s2.str();
if (result.bottom > )
{
ans[i] += "|";
stringstream s3;
s3 << result.bottom;
ans[i] += s3.str();
}
}
}
}
return que;
}

8. 生成答案 string 数组

 string* Core::getAns()
{
if (data_type == )
{
for (int i = ; i <= que_num; i++)
{
for (int j = ; ans[i][j]; j++)
if (ans[i][j] == '.')
{
for (size_t k = j + accuracy + ; k < ans[i].length(); k++)
ans[i][k] = '\0';
break;
}
}
}
return ans;
}

四. 测试

以下测试样例约定生成 20 道题目,每题 10 个运算数,数值范围 0~10,在加、减、乘、除、乘方模式。

1. 整数

 (  -  /  ) * (  +  ^  ) +  ^  - (  +  )
=
/ + - + * - ( + - * )
=
( - + ) * ( - ( ^ - ) ) + + +
=
* ( * - ) - / + + ^ +
=
* ^ + * + * ( + ( - ) * )
=
* ( * - ) * + ( * + - ) *
=
( + ) * ( - ) + ( / + - ) * *
=
( + * ) * + ^ * ( / + / )
=
- / - ( - ) + ^ * ( - / )
=
* - - / + / * * ^
=
/ + + / + * + - ( + )
=
* * ( / + ) + - ( - ) + -
=
* ( - + ) + ^ + + * -
=
+ - - + ( + ) * ( ^ + / )
=
( + - / ) * * + * * ( - )
=
* ( - ) - ( - / ) + * * *
=
+ + / * / + * - /
=
( ^ + / ) * ( + * ) + * ( + )
=
( + ^ ) * ^ * + + + /
=
* / + ( + + ) * ( / - / )
=

View string

2. 小数(精度为 3)

 ( 1.05 -  ^  ) / ( 1.75 * ( 6.1 - 3.2 ) ) + 3.4 + 3.1 + 6.15 + 8.9
= 21.559
( 6.85 + 4.1 ) * 7.2 + 1.65 / ( ^ * 2.9 + 1.45 + 5.6 + 8.05 )
= 78.840
( 9.55 / ( 7.95 - 7.4 ) - 0.65 ) / 7.3 + ( 0.1 + 1.8 ) / ( 9.8 - 3.4 / 6.7 )
= 2.494
1.2 / ( 6.15 + 5.15 - 9.75 - 0.45 ) + 2.9 / ( 9.9 / 9.9 ) * 1.1 / 1.9
= 2.769
( 3.8 - 1.05 ) * 3.75 / ^ + ( 9.25 + 4.4 ) * 7.85 * ^
=
( 4.1 / ( 5.05 * 9.3 ) + 9.25 - 0.4 ) * ^ + 1.1 - ( 2.5 - 2.2 )
= 36.549
3.7 + ^ + 9.6 * + ( 8.6 - 7.15 - 0.1 ) * ( 1.6 + 6.25 )
= 1348.7
4.7 + 8.55 + 3.2 - 2.55 + ( 4.35 - 0.5 ) * ( 5.75 + ( 4.1 + 4.35 ) / 2.15 )
= 51.168
( ^ - 7.65 ) * ^ + 7.85 / 5.4 / ( 0.05 * 9.65 * )
= 390.03
7.95 - 6.45 + ^ + 8.15 * 5.55 + ( 3.75 + 7.1 ) / ( 8.75 - 1.05 )
= 49.141
^ - 0.55 / 3.9 + 6.6 / ^ * ( + 6.75 ) / 7.25
= 93.376
( ^ - 0.05 ) / ( 3.15 - 0.2 ) + 8.55 - 8.2 + 1.6 * 8.75 + 5.65
= 25.406
3.6 / ( ( 8.45 - 1.15 ) / 8.5 + 1.4 * ( 7.15 - 3.15 ) ) + ( 1.05 + 4.4 ) * 9.4
= 51.787
( 1.25 + 7.45 ) / ( ^ / ^ ) + ^ * ^
= 15628.9
^ - ( 4.45 + 2.65 + 2.15 ) + 0.1 * ( 8.45 - ( 9.6 - 7.25 ) * 0.4 )
= 3116.5
^ + 5.5 - ( 4.1 - 1.95 ) + ( 7.05 - 4.45 ) * 9.4 - ( 1.4 - )
= 28.39
^ - 8.2 - ( 3.3 - 0.8 ) + 6.55 * 5.9 * 7.05 / ( 4.05 - 1.5 )
= 160.142
3.3 + 9.8 / 7.9 + 2.9 * 4.9 + 9.6 - ( 3.9 + 2.4 ) * 8.75 / 6.8
= 20.243
4.45 - ( 9.25 + 0.75 - ( 4.65 + ) ) + ( 8.95 + 9.1 ) * 1.3 - 8.05 / 7.9
= 26.546
8.1 / 0.75 / ^ + ( 8.35 - 6.6 ) * ^ / ^
= 4.72

View string

3. 分数

 ( | - | / | ) / ( | * ( | - | ) ) + | + | + | + |
= |
| * | / | + | * | + / ( ^ + | + | )
= |
- | - ( | - | ) * | + ( | - | ) * | * ( | - | )
= |
* ( | - | ) + ( | - | ) * | - ( | + | * | ) * |
= |
| / * ( | - | ) / | / | + | - | / ( | - | )
= |
( | - | ) / ( | * ) + | + | + ( | - | ) * ( | - | )
= |
( | + | - ( | - | ) ) * ( | + | + | ) + | / | + |
= |
| + ^ + | * | + | + | + | + | - |
= |
| + - | - | - ( | - | ) + | * | * | /
= |
^ * | * | + ^ / ( ( | + | ) / ( * | ) )
= |
( - | ) / ( * | + | ) + ^ - | * ^
= |
| - | - ( | - | ) + ( | - | ) / ( ( | + | ) * ( | - | ) )
= |
| * ( - | ) / ( | * | ) * | * | + | * ( - | )
= |
| + | + | - | + ^ + ( | - | * | ) * |
= |
^ + | + ^ * | + | + | * | / |
= |
^ + | - ( | - | ) + ( - | ) / | * ( + | )
= |
| * ( | + | ) * ( | / | - | ) + | / | * | / |
= |
| / | * | * ^ + * ( / | + | - | )
= |
| + + | - | / ( | * | + ) + | / * |
= |
/ ( | - | ) / ( | + | ) + | + | + | - ( | + | )
= |

View string

4. 样例分析

可以看到,我们生成的算数表达式符合参数要求,结构均匀而随机,括号匹配无误,计算结果正确。

五. DLL 封装和对接

参考网上知识,采用 VS2017 创建 DLL 文件,在 .h 头文件中进行类的定义和相关声明,在 .cpp 文件中进行各种成员函数的定义。在完成 DLL 相关配置后,生成新的解决方案,生成相应的 .lib 和 .dll 文件。

编写测试程序,测试 DLL 文件,将 .h .lib 和 .dll 文件复制到相应文件夹,在头文件中引用 .h 文件,在资源文件引用 .lib 文件,在 main 函数中创建对象,引用成员函数,检测成功后给 UI 组初步对接。

与 UI 组进行 DLL 对接时,其中一组曾编译出现 “LNK2019 无法解析的外部符号” 的报错,后来排查得知是 x64 和 x86 平台差异引起,于是我们对 x86 和 x64 分别生成 .lib 和 .dll 文件,解决了这个问题。

 

六. 结对编程感悟

这次结对的过程中 zou 主要完成算术表达式的计算,中缀显示,类的封装,DLL 文件的生成;fan 主要完成算数表达式在各种情况下的生成,API 和博客的撰写。

这次编程非常佛系最后一天上午才完成,然后忙着和 UI 组对接,总的来说结对编程的效率远高于独立作业,我们将思路理顺之后编程非常高效,出现 bug 之后也能及时发现并解决。

面对再一次的编程任务,我们抱以一种佛系的心态,一开始并未着急编写,吸取上次经验,讨论了很多种方案,仔细分析优劣,最终理清思路并梳理了整体的框架,有条不紊地编写时并未出现太多意料之外的困难。

面对问题的处理方式是多种多样的,结对编程优势之一就是,两个人的积极性互相被调动,个人陷入局部困境导致整体目标变模糊的概率也大为减小,与之同时,不论焦急还是从容,死限 DDL 来临的速率是一个常数,所以不妨用更加佛系的心态,减少实际行动中漫无目的或毫无效率忙碌,更多地在思维活跃而清晰之下充分调用自身能力,稳健地去面对。

七. PSP 表格

Personal Software Process Stages 预估耗时(分) 实际耗时(分)
计划 10 10
· 估计这个任务需要多少时间 10 10
开发 1495 1540
· 需求分析 (包括学习新技术) 2h * 60 3h * 60
· 生成设计文档 30 20
· 设计复审 (和同事审核设计文档) 5 5
· 代码规范 (为目前的开发制定合适的规范) 10 5
· 具体设计 30 30
· 具体编码 12h * 60 10h * 60
· 代码复审 30 40
· 测试(自我测试,修改代码,提交修改) 10h * 60 11h * 60
报告 70 60
· 测试报告 30 30
· 计算工作量 10 10
· 事后总结, 并提出过程改进计划 30 20
  1555 1620

  

佛系结对编程---四则运算(Core 第四组)的更多相关文章

  1. 20175305张天钰Java结对编程四则运算(二)

    Java结对编程四则运算(二) 一.题目描述及要求 Git提交粒度不要太粗,建议一个文件/一个类/一个函数/一个功能/一个bug修复都进行提交,不能一天提交一次,更不能一周一次,参考Commit Me ...

  2. 20175305张天钰Java结对编程四则运算

    Java结对编程四则运算 一.题目描述:如何对表达式进行求值运算呢 1.中缀表达式与后缀表达式(娄老师讲解) 中缀表达式就是运算符号在运算数中间的表达式,比如1+2,顾名思义,后缀表达式就是运算符在运 ...

  3. 王译潇20162314 实验报告三plus结对编程四则运算第一阶段

    北京电子科技学院BESTI实验报告 课程:程序设计与数据结构 班级: 1623 姓名: 王译潇 学号:20162314 指导教师:娄佳鹏老师.王志强老师 实验日期:2017年5月12号 实验密级: 非 ...

  4. 20175226 2018-2019-2《java程序设计》结对编程-四则运算(第一周-阶段总结)

    结对编程-四则运算(第一周-阶段总结) 需求分析 实现一个四则运算程序,要求: 自动随机生成小学四则运算题目(加,减,乘,除) 支持整数.真分数且支持多项式 能够利用栈的思想,将中缀转换为后缀表达式 ...

  5. 结对编程--四则运算(Java)萧英杰 夏浚杰

    结对编程--四则运算(Java)萧英杰 夏浚杰 Github项目地址 功能要求 题目:实现一个自动生成小学四则运算题目的命令行程序 使用 -n 参数控制生成题目的个数(实现) 使用 -r 参数控制题目 ...

  6. 结对编程--四则运算(Java)梅进鹏 欧思良

    结对编程--四则运算(Java)梅进鹏 欧思良 Github项目地址:https://github.com/MeiJinpen/Arithmetic 功能要求 题目:实现一个自动生成小学四则运算题目的 ...

  7. Java结对编程四则运算一周小结

    Java结对编程四则运算一周小结 需求分析 对于四则运算来说最主要的就是要计算出产生的式子(字符串的形式). 设计思路 总体可将这个项目分解为几个部分:产生式子,计算式子,判断对错并记录: 具体的思路 ...

  8. 结对编程项目总结(core2组)

    结对编程项目总结(core2组) 作业---四则运算(Core 第二组)   ----by 吴雪晴 PB16061514 齐天杨 PB16060706 一.项目简介 项目的任务为制作一个给(貌似是?) ...

  9. 结对编程四则运算gui

    码市地址:https://git.coding.net/linzhao/sizeyunsuangui.git 林 钊 -- 201421123105 吴世荣 -- 201421123119 王坤彬 - ...

随机推荐

  1. eAccelerator 配置参数详解

    eAccelerator配置参数如下: [eaccelerator]extension=eaccelerator.soeaccelerator.shm_size="64"eacce ...

  2. bundle 与 package

    bundle是Apple提供的软件安装的便捷方法. bundle为用户和开发者提供了一个简单地接口. bundle 和 package package:看起来像一个文件的目录       bundle ...

  3. python 实现dns 解析发送接收报文

    http://www.qingruxu.com/code/python/851.html https://tools.ietf.org/html/rfc1035里面的图不一定正确,可以使用抓包软件来进 ...

  4. 局域网电脑之间ping不通解决办法

    局域网电脑之间ping不通一般都是防火墙的原因.解决办法有以下两种方法 1 第一种方法 1 找到Windows防火墙 2点击更改通知设置 3 关闭专用网络防火墙 现在就可以ping通这台机器了. 2  ...

  5. 搭建简单FTP

    搭建简单FTP 环境 CentOS 7 安装 yum install vsftpd 修改配置文件, 在/etc/vsftpd/vsftpd.conf中添加allow_writeable_chroot= ...

  6. golang 读取一行

    //读取一行 func myReadLine(paths string) error { //先获取到文件信息 fileinfo, err := os.Stat(paths) if err != ni ...

  7. 「Sdchr 的邀请赛」题解

    骗个访问量.. A:取石子 将点 x 与点 x / prime 连边,那么这个图可以由指数之和的奇偶性来划分成一个二分图. 接下来考虑推广阶梯 NIM (或者这原本就是阶梯 NIM ?),必胜当且仅当 ...

  8. canvas绘制经典星空连线效果

    来自:https://segmentfault.com/a/1190000009675230 下面开始coding:先写个canvas标签 <canvas height="620&qu ...

  9. Windows Server 2008 R2系统上安装SQLServer2012集群(简略)

    4台服务器(1台AD.2台SQL服务器.1台iSCSI存储服务器) 9个IP(1个AD的IP.2个SQL服务器的IP.2个心跳IP.1个iSCSI存储服务器的IP.1个集群IP.1个DTC的IP.1个 ...

  10. Silverlight & Blend动画设计系列六:动画技巧(Animation Techniques)之对象与路径转化、波感特效

    当我们在进行Silverlight & Blend进行动画设计的过程中,可能需要设计出很多效果不一的图形图像出来作为动画的基本组成元素.然而在设计过程中可能会出现许多的问题,比如当前绘制了一个 ...