一,成员信息表
作业链接 | https://edu.cnblogs.com/campus/gdgy/CSGrade21-34/homework/13025 |
---|---|
拜尔克吐拉·吾买尔江 | 3121005247 |
阿布都瓦力·努尔买合买提 | 3121005072 |
Github链接 | https://github.com/bayer12/3121005247-bayer |
二,PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | 20 | 20 |
· Estimate | · 估计这个任务需要多少时间 | 10 | 10 |
·Development | ·开发 | 120 | 100 |
· Analysis | · 需求分析 (包括学习新技术) | 60 | 60 |
· Design Spec | 生成设计文档 | 20 | 20 |
· Design Review | · 设计复审 (和同事审核设计文档) | 10 | 10 |
· Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 5 | 10 |
· Design | · 具体设计 | 30 | 50 |
· Coding | · 具体编码 | 180 | 200 |
· Code Review | · 代码复审 | 20 | 15 |
· Test | · 测试(自我测试,修改代码,提交修改) | 20 | 20 |
Reporting | 报告 | 30 | 30 |
· Test Report | · 测试报告 | 20 | 15 |
· Size Measurement | · 计算工作量 | 10 | 10 |
· Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 30 | 30 |
合计 | 585 | 600 |
三,关键代码和设计说明
数据的定义
typedef struct variable
{
int num_or_Symbol; //0是数字1是符号
int Symbol = -1; // + - * % ( ) 分别表示为 0 1 2 3 4 5
int numer; //如果是数字此为分子
int Den = 1; //如果是数字此为分母
int num; //如果是数字此为分数前的系数
bool operator == (variable c){
return num_or_Symbol == c.num_or_Symbol && Symbol == c.Symbol && numer == c.numer && Den == c.Den && num == c.num;
}
}var;
主要的几个部分如下
//生成表达式函数
Status Create(var** exp, int size, int *length);
//计算表达式函数
Status Calculation(var* exp, int size, var* result, int length);
//中缀表达式转后缀表达式
Status Infix_to_Postfix(var* p, int size, var* Postfix, int length, int& postLen);
//判断两个问题是否等价
Status is_question_same(var* Question, int lenQuest, var* newQuestion, int lenNewQuest, int size);
//m指令的执行
void M_instructions(var** expression, int amount, int size, var* result);
//判断对错
void Correction(int* save, char* answerfile, char* exercisefile);
关键代码
创建题目
Status Create(var** exp, int size, int* length)
{
var* expre;
int mark_num = random(1, 4);//计算符个数
int pre = 0;//前括号在第pre个数字前
int aft = 0;//后括号在第aft个数字后
int judge = 0;//判断,0写入数字,1写入符号
int n = 0;
*length = mark_num + mark_num + 1;
n = 0;
if (mark_num > 1)//如果运算符有3个,则存在括号
{
pre = random(1, mark_num);
if(pre == 1)//不让括号括住整个式子
aft = random((pre + 1), (mark_num + 1));
else
aft = random((pre + 1), (mark_num + 2));
(*length) += 2;
expre = new var[*length + 1];
expre[pre * 2 - 2].num_or_Symbol = 1;
expre[pre * 2 - 2].Symbol = 4;
expre[aft * 2].num_or_Symbol = 1;
expre[aft * 2].Symbol = 5;
}
else
{
expre = new var[*length + 1];
}
n = 0;
while (n < *length)
{
if (expre[n].Symbol < 4)
{
if (judge == 0)
{
expre[n].num_or_Symbol = 0;
expre[n].Den = random(2, size);
expre[n].numer = random(0, expre[n].Den);
expre[n].num = random(1, size);
judge = 1;
}
else
{
expre[n].num_or_Symbol = 1;
expre[n].Symbol = random(0, 4);
judge = 0;
}
}
n++;
}
*exp = expre;
return SUCCESS;
}
中缀表达式转后缀表达式
Status Infix_to_Postfix(var* p, int size, var* Postfix, int length, int& postLen)
{
//传入的postfix要记得为空
var stack[maxn];
int top = 0;
for (int i = 0; i < length; i++)
{
if (p[i].num_or_Symbol == 0)//是数字
{
Postfix[postLen++] = p[i];//放入输出串中
}
if (p[i].num_or_Symbol == 1 && p[i].Symbol == 4)//左括号
{
++top;
stack[top] = p[i];
}
while (p[i].num_or_Symbol == 1 && p[i].Symbol != 4 && p[i].Symbol != 5)
{
if (top == 0 || stack[top].Symbol == 4 || prio(p[i]) > prio(stack[top]))
{
++top;
stack[top] = p[i];
break;
}
else
{
Postfix[postLen++] = stack[top];
top--;
}
}
if (p[i].num_or_Symbol == 1 && p[i].Symbol == 5)//右括号
{
while (stack[top].Symbol != 4)
{
Postfix[postLen++] = stack[top];
top--;
}
top--;
}
}
while (top != 0)
{
Postfix[postLen++] = stack[top--];
}
return SUCCESS;
}
判断题目是否等价
Status is_problem_same(var* Question, int lenQuest, var* newQuestion, int lenNewQuest, int size)
{
var Postfix1[maxn], Postfix2[maxn];
var stack1[3][3], stack2[3][3];
int len1 = 0, len2 = 0, sta_size1 = 0, sta_size2 = 0;
//获取后缀表达式
Infix_to_Postfix(Question, size, Postfix1, lenQuest , len1);
Infix_to_Postfix(newQuestion, size, Postfix2, lenNewQuest, len2);
//获取子表达式
get_Subexpression(Postfix1, len1, stack1, sta_size1);
get_Subexpression(Postfix2, len2, stack2, sta_size2);
bool flag;
for (int i = 0; i < sta_size1; i++)
{
flag = false;
for (int j = 0; j < sta_size2; j++)
{
//短式等价
if (cmp(stack1[i], stack2[j]))
{
flag = true;
stack2[j][2].Symbol = -1;//将表达式的运算符删掉
break;
}
}
if (!flag)//如果存在不一样的,返回not same
{
return ERROR;
}
}
return SUCCESS;
}
m操作
void M_instructions(var **expression, int amount, int size, var* result)
{
fstream answer;
answer.open(ANSWERFILE, ios::out | ios::app);
var results[maxn];//后缀表达式
int length;
int i = 0;
int j = 0;
int k = 0;
while (i < amount)
{
Create(&expression[i], size, &length);
result[i].Symbol = length;
if (Calculation(expression[i], size, results, length) == ERROR || results[0].num >= size || results[0].numer >= size || results[0].Den >= size)
{
continue;
}
result[i].Den = results[0].Den;
result[i].num = results[0].num;
result[i].numer = results[0].numer;
result[i].num_or_Symbol = 0;
result[i].Symbol = length;
j = 0;
while (j < i)
{
//结果一样,表达式可能一样
if (result[j].Den == result[i].Den && result[j].numer == result[i].numer && result[j].num == result[i].num)
{
if (is_question_same(expression[i], result[i].Symbol, expression[j], result[j].Symbol, size))
{
break;
}
}
j++;
}
if (i != j)
{
if(k ++ < 20)//连续20次重复答案表明给的size太小,而amount太大,表达式多样性不足
continue;
}
Visit(expression[i], length, i + 1);
answer << i + 1 << ". ";
if (result[i].numer == 0)
{
answer << result[i].num;
}
else
{
if (result[i].num != 0)
{
answer << result[i].num;
answer << "`";
}
answer << result[i].numer;
answer << "/";
answer << result[i].Den;
}
answer << endl;
i++;
k = 0;
}
answer.close();
}
四,测试运行
随机生成10道题目
改变题目数值后随机生成10道题目
测试在exercisefile.txt文件内填入答案后判断对错
五,项目小结
通过这次的结对编程,使我们对编程有了新的认识,在双人模式下,一个人一边写代码,一边说思路,另一个人在旁听,旁听的同学通过边听边看,能发现打代码同学可能出现的一些bug进而及时修正,减少错误可能发生的概率,提升了工作效率。
同时在结对编程的过程中,对于同一个问题可能会有不同的解决办法,通过讨论,我们能得出相对较优的算法,进而提升程序的效率。
同时由于常用语言的不同,在转化方面我们更要去认真了解不同语言实现同一个函数功能之间的差异。