2023软件工程第二次作业(结对编程)

2024-02-14 18:30

本文主要是介绍2023软件工程第二次作业(结对编程),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

姓名:李英磊    学号:M23182606

姓名:邵卓承    学号:M23182705

       按课程要求完成结队编程四则运算自动生成题目与答案并且自动判卷的项目。

       我们的项目仓库代码如下:李英磊/邵卓承结对编程代码仓库。

       整个项目工程中做的具体分工如下:

       李英磊:创建仓库、需求分析、完成代码、仓库管理、协助完成博客

       邵卓承:学习代码、代码分析、根据需求改进优化代码、撰写博客

一、PSP个人开发流程表格

PSPPersonal Software Process Stages预估耗时实际耗时
Planning计划1010
Estimate估计这个任务需要多少时间1010
Development开发200150
Analysis需求分析50100
Coding代码规范2025
Code Review代码复审2020
Test测试1010
Reporting报告3030
Test Repor测试报告1010
Size Measurement计算工作量1010
Postmortem & Process Lmprovement plan事后总结,并提出过程改进计划2020
合计390395

二、 工程进行中学习日志以及对题目的思考

(一)学习过程

邵卓承:

10.16——学习使用可视化工具TortoiseGit上传与下载码云仓库代码(时间1、2、9、10节课)

       学习进度:已基本学会使用,并且通过实践。

       评价:但是由于缺乏常识,学习效率低。

10.17—— 通过bilbili网课学习码云仓库的里程碑、任务发布以及commit等操作(时间1,2节课)

       学习进度:完成学习,并完成相关任务。

       评价:任务简单,完成容易。

10.18——尝试读懂下载的代码,并考虑八条需求中哪些可以简单通过改动完成(时间3、4节课)

       学习进度:通过各种手段基本弄清每个函数的功能,并且能过通过改动一些值改变代码部分功能

       评价:并未完全吃透代码,只是以使用者的角度对代码进行理解 

10.19——更改和调整部分代码,学习分析VS的效能分析图(时间1、2、3、4节课)

       学习进度:对代码进行了微调,效能分析的学习过程中了解到大量分析软件,VS效能分析图能够初步理解意义

       评价:能基本完成任务需求,但是不够精通

10.20——写博客(时间1,2节课)

       学习进度:基本完成整体的博客撰写

       评价:较高效

10.21——完善博客(时间1、2节课)

       学习进度:完成两人沟通与合作,完成博客撰写

       评价:较高效

李英磊:

10.16——创建自己的仓库,在互联网查资料并寻找合适的代码(时间1、2节课)

       学习进度:查阅资料,加强知识巩固

       评价:高效

10.17——读懂代码,将下载的代码进行改进,并考虑需求中简单的一部分(时间3、4节课)

       学习进度:对代码进行基本的改进并能完成一些简单需求

       评价:高效

10.18——将下载的代码进一步改进,并考虑加入更多需求(时间1、2节课)

       学习进度:进一步改进代码并能完成更多需求

       评价:高效

10.19——对代码进行效能分析并编写PSP表格(时间3、4节课)

       学习进度:查找资料对代码进行效能分析完成对PSP表格的编写

       评价:高效

10.20——写博客(时间9、10节课)

       学习进度:对博客的内容进行编写

       评价:高效

10.21——完善博客(时间1、2节课)

       学习进度:进一步完善对博客内容的编写

       评价:高效

(二)对题目的思考 

        根据代码的八条需求:

  1. 题目数量可以指定。
  2. 支持加减乘除4种运算。
  3. 每道题包含两个运算符
  4. 运算数为100 以内的数字。
  5. 保证答案在 0..100 之间。
  6. 需要有答题功能并验证答案是否正确。
  7. 判分,并对历史成绩进行存储和查询。
  8. 题目避免重复。

        除此之外还有一条附加需求:题目含有可嵌套括号,以改变运算优先级

        根据以上需求,以及代码出题、出答案、给出答题结果的功能将代码算法设计如下:

       根据需求中的几项,无疑生成题目阶段需要实现的功能很多,比如判断分母不能为0,出的题目不能重复,随机插入前括号,然后根据前括号位置插入后括号,以及题目中的运算数的类型以及大小,这些都需要在出题阶段实现限制与操作。其中读取文件、写入文件等也是难点之一。

       根据这些需求,由于编程基础较差,对于文件相关编程的操作不熟悉,对随机数以及字符串的操作也不熟练,所以考虑在网上拷贝功能相似的代码,并且理解代码,并在其基础上修改以达到代码的功能以及需求。

三、代码设计与解读

(一)创建文档以及代码与文档建立联系

#define EXERCISEFILE	"exercisefile.txt"
#define ANSWERFILE		"answerfile.txt"
#define GRADE			"grade.txt"

(二) 初始化文档

remove(EXERCISEFILE);
remove(ANSWERFILE);

(三)输入操作代码以及参数

默认设置出题数值范围为100:

int size = 100;	//计算数的取值范围

输入-n设置出题数量:

case 'n'://控制生成题目的个数n = 2;while (instructions[n] == ' ' && n < 300) n++;if (n == 2 || n == 300){cout << "指令输入有误,请重新输入!\n";break;}i = 10;amount = 0;while (instructions[n] != '\0' && instructions[n] >= '0' && instructions[n] <= '99' && n < 300){j = instructions[n] - '0';amount = j + amount * i;n++;}if (amount < 1 && n == 300 && amount > MAX_LENGTH){cout << "数据输入有误,请重新输入!\n";break;}remove(EXERCISEFILE);remove(ANSWERFILE);M_instructions(expression, amount, size, result);Destrory(expression, result, amount);break;

 输入-r设置每个数字的大小范围

case 'r'://控制题目中数值(自然数、真分数和真分数分母)的范围n = 2;while (instructions[n] == ' ' && n < 300) n++;size = 0;if (n == 2 || n == 300){cout << "指令输入有误,请重新输入!\n";break;}while (instructions[n] != '\0' && instructions[n] >= '0' && instructions[n] <= '99' && n < 300){size = instructions[n] - '0' + size * 10;n++;}if (size <= 0 || n == 300){size = 100;cout << "数据输入有误,请重新输入!\n";}break;

(四)生成题目与答案

        生成题目、答案、写入文档操作的代码如下:

        随机生成随机题目表达式的代码如下:

Status Create(var** exp, int size, int* length)
{var* expre;int mark_num = 2;//计算符个数int pre = 0;//前括号在第pre个数字前int aft = 0;//后括号在第aft个数字后int judge = 0;//判断,0写入数字,1写入符号int n = 0;*length = mark_num + mark_num + 1;n = 0;//如果运算符有3个,则存在括号if (mark_num > 1){pre = random(1, 3);if (pre == 1)//不让括号括住整个式ziaft = random((pre + 1), (mark_num + 1));elseaft = 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;
}void Visit(var* expression, int length, int num)
{fstream exercise;exercise.open(EXERCISEFILE, ios::out | ios::app);exercise << num << ".   ";int n = 0;while (n < length){if (expression[n].num_or_Symbol == 0){if (expression[n].numer == 0){cout << expression[n].num;exercise << expression[n].num;}else{if (expression[n].num != 0){cout << expression[n].num;cout << "`";exercise << expression[n].num;exercise << "`";}cout << expression[n].numer;cout << "/";cout << expression[n].Den;exercise << expression[n].numer;exercise << "/";exercise << expression[n].Den;}}else{switch (expression[n].Symbol){case 0:cout << " + ";exercise << " + ";break;case 1:cout << " - ";exercise << " - ";break;case 2:cout << " × ";exercise << " × ";break;case 3:cout << " ÷ ";exercise << " ÷ ";break;case 4:cout << '(';exercise << '(';break;case 5:cout << ')';exercise << ')';break;default:break;}}n++;}cout << " = \n";exercise << " = ";exercise << endl;exercise.close();
}

       其中,控制括号的代码行 

case 4:cout << '(';exercise << '(';break;
case 5:cout << ')';exercise << ')';break;

       由代码可见,该代码生成的随机数为分数,符号包含了四则运算,且避免了分母为0的情况。

       通过答案是否相等来初步判断题目是否重复的功能,代码如下:

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();
}

        根据文本内容判断是否答题正确的代码如下:

void Correction(int* save, char* answerfile, char* exercisefile)// -e exercisefile.txt -a answerfile.txt
{fstream answer;fstream exercise;fstream grade;answer.open(answerfile, ios::in);if (!answer){cout << "答案文件不存在!\n";return;}exercise.open(exercisefile, ios::in);if (!exercise){cout << "题目文件不存在!\n";return;}grade.open(GRADE, ios::out | ios::app);char answ[100];char exer[100];int i, j;int n, m;int correct = 0;int wrong = 0;while (!answer.eof() && !exercise.eof()){answer.getline(answ, 100);//读取整行exercise.getline(exer, 100);i = 0, j = 0, n = 0, m = 0;while (answ[i] >= '0' && answ[i] <= '9')n = answ[i++] - '0' + n * 10;while (exer[j] >= '0' && exer[j] <= '9')m = exer[j++] - '0' + m * 10;if (n == m){if (n != 0 && n <= MAX_LENGTH){i = 0;j = 0;while (exer[j++] != '=' && j < 100);while (exer[j++] == ' ' && j < 100);while (answ[i++] != '.' && i < 100);while (answ[i++] == ' ' && i < 100);j -= 1;i -= 1;while (exer[j] != ' ' && exer[j] != '\t' && exer[j] != '\0' && i < 100 && j < 100){if (answ[i++] != exer[j++])break;}if (answ[i - 1] == exer[j - 1] && exer[j - 1] != ' ' && answ[i] == '\0'){save[n] = 1;save[n + 1] = -1;correct++;}else{save[n] = 0;save[n + 1] = -1;wrong++;}}}else{if (n == 0 && m != 0)n = m;if (m == 0 && n != 0)m = n;cout << "操作失败!文件" << ANSWERFILE << "第" << n << "题或" << EXERCISEFILE << "第" << m << "题发生错误!\n";return;}}i = 1, j = 0;grade << "Correct: " << correct << " (";while (save[i] >= 0){if (save[i] == 1){if (j != 0)grade << ',';elsej = 1;grade << i;}i++;}grade << ")" << endl;i = 1, j = 0;grade << "Wrong: " << wrong << " (";while (save[i] >= 0){if (save[i] == 0){if (j != 0)grade << ',';elsej = 1;grade << i;}i++;}grade << ")" << endl;cout << "数据已录入" << GRADE << "!\n";answer.close();exercise.close();grade.close();
}void Destrory(var** expression, var* result, int amount)
{int i = 0;while (i < amount)free(expression[i++]);

        随机括号的位置,增加解题的难度,代码如下:

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;
}int prio(var element)
{if (element.Symbol == 0 || element.Symbol == 1)return 1;if (element.Symbol == 2 || element.Symbol == 3)return 2;return 0;
}

        分数的通分运算,生成答案并将答案写入文档的过程,代码如下:

void preprocess(var& a, var& b)
{//将前面的系数加进分母if (a.num != 0){a.numer += a.num * a.Den;a.num = 0;}if (b.num != 0){b.numer += b.num * b.Den;b.num = 0;}//分母通分a.numer *= b.Den;b.numer *= a.Den;a.Den = b.Den = a.Den * b.Den;
}int get_gcd(int a, int b) {return b == 0 ? a : get_gcd(b, a % b);
}Status calc(var* Postfix, int length, var& ans)
{var stack[maxn];//存放操作数int top = 0;for (int i = 0; i < length; i++)//遍历后缀表达式{if (Postfix[i].num_or_Symbol == 0)//是操作数{stack[top++] = Postfix[i];}else if (Postfix[i].num_or_Symbol == 1)//是运算符{if (top < 2)//判断一下操作数是否足够两个,不足够则报错{printf("发生错误,操作数不足,无法完成运算\n");exit(-1);}var ret;if (!operate(stack[top - 2], stack[top - 1], Postfix[i], ret))//计算过程有负数 || 计算过程中出现了除 0 的非法操作{return ERROR;}top -= 2;stack[top++] = ret;}}if (top == 1)//最后肯定只剩一个数字{ans = stack[0];return SUCCESS;}//printf("计算到最后,栈中剩余的操作数不为一个\n");return ERROR;
}Status operate(var a, var b, var oper, var& ret)
{//先通分preprocess(a, b);//判断执行的操作if (oper.Symbol == 0)//+{a.numer += b.numer;}else if (oper.Symbol == 1)//-{a.numer -= b.numer;}else if (oper.Symbol == 2)// *{a.numer *= b.numer;a.Den *= b.Den;}else if (oper.Symbol == 3)// ÷{a.numer *= b.Den;a.Den *= b.numer;}if (a.numer < 0 || a.Den == 0)//计算过程中出现了负数 || 计算过程中出现了除 0 的非法操作{return ERROR;}//化简ret = a;int gcd = get_gcd(ret.numer, ret.Den);ret.numer /= gcd, ret.Den /= gcd;ret.num = ret.numer / ret.Den;ret.numer %= ret.Den;return SUCCESS;
}void display(var* a) {if (a->num == 0){if (a->Den == 1){printf("%d\n", a->numer);}else {printf("%d/%d\n", a->numer, a->Den);}}else {if (a->Den == 1){printf("%d\n", a->numer + a->num);}else {printf("%d'%d/%d\n", a->num, a->numer, a->Den);}}
}void crerat_info(var* expression, int i, int num_or_Symbol, int numer, int den, int Symbol, int num)
{expression[i].num_or_Symbol = num_or_Symbol;expression[i].Den = den;expression[i].numer = numer;expression[i].Symbol = Symbol;expression[i].num = num;
}void print(var* result, int len)
{for (int i = 0; i < len; i++){if (result[i].num_or_Symbol == 0){printf("%d", result[i].numer);}else {if (result[i].Symbol == 0){printf("+");}else if (result[i].Symbol == 1){printf("-");}else if (result[i].Symbol == 2){printf("*");}else if (result[i].Symbol == 3){printf("÷");}}}puts("");
}
//计算表达式函数
Status Calculation(var* exp, int size, var* result, int length)
{int postLen = 0;Infix_to_Postfix(exp, size, result, length, postLen);var ans;if (!calc(result, postLen, ans)){return ERROR;}*result = ans;return SUCCESS;
}Status get_Subexpression(var* Postfix, int length, var ans[][3], int& sta_size)
{var stack[maxn];//存放操作数int top = 0;for (int i = 0; i < length; i++)//遍历后缀表达式{if (Postfix[i].num_or_Symbol == 0)//是操作数{stack[top++] = Postfix[i];}else if (Postfix[i].num_or_Symbol == 1)//是运算符{var ret;ans[sta_size][0] = stack[top - 2];ans[sta_size][1] = stack[top - 1];ans[sta_size++][2] = Postfix[i];operate(stack[top - 2], stack[top - 1], Postfix[i], ret);top -= 2;stack[top++] = ret;}}return SUCCESS;
}

        判断随机题目是否一样,代码如下:

bool cmp(var a[], var b[])
{//判断子表达式是否等价if (a[2] == b[2])//运算符{if (a[0] == b[1] && a[1] == b[0] || (a[0] == b[0] && a[1] == b[1]))//操作数{return true;}}return false;
}
//判断两个问题是否等价
Status is_question_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;
}

        生成题目与答案的运行结果如下图所示:

(五)做题

 

        如图,将答案写入题目txt文件,题目正确三题,错误一题,未答六题 。

(六)批改

        对运行输入-e+题目文件名+答案文件名对做题进行批改,并将结果写入文档。

case 'e':char exercisefile[100];char answerfile[100];n = 2;while (instructions[n] == ' ' && n < 300) n++;if (n == 2){cout << "指令输入有误,请重新输入!\n";break;}i = n;while (instructions[n] != ' ' && n - i < 100 && n < 300 && instructions[n] != '\0'){exercisefile[n - i] = instructions[n];n++;}exercisefile[n - i] = '\0';while (instructions[n] == ' ' && n < 300) n++;if (instructions[n] != '-' || instructions[n + 1] != 'a'){cout << "指令输入有误,请重新输入!\n";break;}n = n + 2;i = n;while (instructions[n] == ' ' && n < 300) n++;if (i == n){cout << "指令输入有误,请重新输入!\n";break;}i = n;while (instructions[n] != ' ' && n - i < 100 && n < 300 && instructions[n] != '\0'){answerfile[n - i] = instructions[n];n++;}answerfile[n - i] = '\0';if (n == 300){cout << "指令输入过长,请重新输入!\n";break;}Correction(save, answerfile, exercisefile);break;
default:cout << "指令输入有误,请重新输入!\n";break;
}

        如图,对上图的做题结果统计出正确个数与题号和错误个数与题号。

四、代码性能分析以及改进

(一)单元测试

1.输入错误指令

2.输入超范围数值

3.生成式子数量等于零、小于零、大于零和等于10的情况,小于等于零是否按0算

4.设置运算数大小成功后出题,运算数是否对应设置值

5.设置运算数大小失败后出题,运算数是否恢复默认值

6.文本生成是否正确,答案的计算值和手动计算一致

7.批改是否能识别,答题结果是否能存储

  

(二)性能分析

         代码中所有内部函数的运行次数以及运行占比如图所示。

 (三)改进

        由于代码非常复杂,且在编译器中运行没有错误,加之小组内人员水平有限,从代码效能的角度对代码进行改进存在困难,故对代码的功能实现更改以贴合需求。

        基于需求中计算数范围为0-100对代码进行了修改,改动如下。

        默认数据范围更改:

int size = 100;//10;	//计算数的取值范围cout << "注:运算数大小默认为小于100的正自然数,可使用指令更改为任意大于0小于2147483647的整数!\n";

        设置数值错误后恢复的数值更改: 

if (size <= 0 || n == 300)
{size = 100;// 10;cout << "数据输入有误,请重新输入!\n";
}

        综合后代码满足了七个需求: 

  1. 题目数量可以指定。
  2. 支持加减乘除4种运算
  3. 每道题包含两个运算符
  4. 运算数为100 以内的数字
  5. 需要有答题功能并验证答案是否正确
  6. 判分,并对历史成绩进行存储和查询
  7. 题目避免重复

五、学习心路历程与收获

(一)工程项目历程

        编辑里程碑并分配任务

        对代码仓库的一些操作,两根共同在一个分支中作业每次编程都重新同步拉取代码,编辑后再上传 。

 

 (二)学习心路历程以及收获

        邵卓承:

        项目开始初期,由于受本课程相关专业同学的启发,对码云的代码克隆、拉取、推送有了一个更深入的认识,并且了解到有小乌龟这样一个可视化工具,帮助代码的管理,由于缺乏计算机相关的一些常识性知识,学习起来历经坎坷,花了四个学时才学会使用,但对后面结对编程有很大帮助,也是一大收获。

       在找代码、读代码阶段,有些语言不太理解,通过在网上搜索、在一些平台看网课、并且询问了一些本专业高中同学帮助理解,学会了一些新功能的库以及语言,但是对于头文件源文件以及读取文本等的依然理解不深,仍然需要时间深入学习。

       初步尝试了利用码云平台,以一个管理者身份对一个工程仓库进行操作,编辑里程碑,拉取合作者,分配任务等操作,对一个项目的创建有了一个初步的认识。

       写代码水平毋庸置疑仍然是迫在眉睫的困境,在课程学习的短短六周内虽然有很大的进步,但仍然需要继续学习。由于对课程理解的偏差,选修此课程的收获有些背离了初衷,但是也极大程度地拓宽了视野,了解了软件工程行业内地基本流程与情况,也让我对编程有了兴趣,对将来我的专业学习有一定帮助。

       这门课程的学习对我来说无疑是一项挑战,但课程具有趣味性,我也愿意花时间和精力来钻研和学习课程的本领,了解课程的历史与现状,经过了五周痛并快乐的学习我感觉受益匪浅,给我开启了一扇崭新的大门。在以后的课程学习过程中以及最后的小组编程中,我仍会保有高涨的热情,也希望能有很多收获。

       李英磊:

       第一次面对有一定难度的项目有一些手足无措,但随着后来学习的深入,发现其实也并没有想象的那么难,加上有同学老师的帮助,完成这个项目变得更简单些,自己从一个对软件工程什么都不懂的小白也逐渐变得入门。

       软件工程课程拓宽了我的视野。在课堂上,我们学习了软件开发的整个过程,包括需求分析、设计、编码、测试和维护等环节。通过学习这些内容,我明白了软件开发不仅仅是编写代码,还需要考虑用户需求、系统设计和质量保证等方面。软件工程课程让我认识到,一个好的软件开发团队应该具备合理的组织架构和良好的团队合作能力,才能开发出高质量的软件。


       软件工程课程提高了我的实践能力。课程中,我们进行了一些实践项目,从需求分析到软件开发,再到测试和维护。通过这些实践项目,我不仅巩固了理论知识,还学会了如何将理论应用到实际项目中。在实践中,我遇到了很多问题,比如需求不明确、设计不合理等,但是通过团队的努力和老师的指导,我逐渐掌握了解决问题的方法和技巧。这些实践项目对我来说是一次宝贵的经验积累,提高了我的实践能力和解决问题的能力。

六、第二次需求增加改动部分

控制括号的代码行 

case 4:cout << '(';exercise << '(';break;
case 5:cout << ')';exercise << ')';break;

  随机括号的位置,增加解题的难度,代码如下:

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;
}int prio(var element)
{if (element.Symbol == 0 || element.Symbol == 1)return 1;if (element.Symbol == 2 || element.Symbol == 3)return 2;return 0;
}

生成题目如图所示 

这篇关于2023软件工程第二次作业(结对编程)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/709251

相关文章

作业提交过程之HDFSMapReduce

作业提交全过程详解 (1)作业提交 第1步:Client调用job.waitForCompletion方法,向整个集群提交MapReduce作业。 第2步:Client向RM申请一个作业id。 第3步:RM给Client返回该job资源的提交路径和作业id。 第4步:Client提交jar包、切片信息和配置文件到指定的资源提交路径。 第5步:Client提交完资源后,向RM申请运行MrAp

Linux 网络编程 --- 应用层

一、自定义协议和序列化反序列化 代码: 序列化反序列化实现网络版本计算器 二、HTTP协议 1、谈两个简单的预备知识 https://www.baidu.com/ --- 域名 --- 域名解析 --- IP地址 http的端口号为80端口,https的端口号为443 url为统一资源定位符。CSDNhttps://mp.csdn.net/mp_blog/creation/editor

【Python编程】Linux创建虚拟环境并配置与notebook相连接

1.创建 使用 venv 创建虚拟环境。例如,在当前目录下创建一个名为 myenv 的虚拟环境: python3 -m venv myenv 2.激活 激活虚拟环境使其成为当前终端会话的活动环境。运行: source myenv/bin/activate 3.与notebook连接 在虚拟环境中,使用 pip 安装 Jupyter 和 ipykernel: pip instal

【编程底层思考】垃圾收集机制,GC算法,垃圾收集器类型概述

Java的垃圾收集(Garbage Collection,GC)机制是Java语言的一大特色,它负责自动管理内存的回收,释放不再使用的对象所占用的内存。以下是对Java垃圾收集机制的详细介绍: 一、垃圾收集机制概述: 对象存活判断:垃圾收集器定期检查堆内存中的对象,判断哪些对象是“垃圾”,即不再被任何引用链直接或间接引用的对象。内存回收:将判断为垃圾的对象占用的内存进行回收,以便重新使用。

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

深入理解RxJava:响应式编程的现代方式

在当今的软件开发世界中,异步编程和事件驱动的架构变得越来越重要。RxJava,作为响应式编程(Reactive Programming)的一个流行库,为Java和Android开发者提供了一种强大的方式来处理异步任务和事件流。本文将深入探讨RxJava的核心概念、优势以及如何在实际项目中应用它。 文章目录 💯 什么是RxJava?💯 响应式编程的优势💯 RxJava的核心概念

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [

函数式编程思想

我们经常会用到各种各样的编程思想,例如面向过程、面向对象。不过笔者在该博客简单介绍一下函数式编程思想. 如果对函数式编程思想进行概括,就是f(x) = na(x) , y=uf(x)…至于其他的编程思想,可能是y=a(x)+b(x)+c(x)…,也有可能是y=f(x)=f(x)/a + f(x)/b+f(x)/c… 面向过程的指令式编程 面向过程,简单理解就是y=a(x)+b(x)+c(x)

Java并发编程之——BlockingQueue(队列)

一、什么是BlockingQueue BlockingQueue即阻塞队列,从阻塞这个词可以看出,在某些情况下对阻塞队列的访问可能会造成阻塞。被阻塞的情况主要有如下两种: 1. 当队列满了的时候进行入队列操作2. 当队列空了的时候进行出队列操作123 因此,当一个线程试图对一个已经满了的队列进行入队列操作时,它将会被阻塞,除非有另一个线程做了出队列操作;同样,当一个线程试图对一个空

生信代码入门:从零开始掌握生物信息学编程技能

少走弯路,高效分析;了解生信云,访问 【生信圆桌x生信专用云服务器】 : www.tebteb.cc 介绍 生物信息学是一个高度跨学科的领域,结合了生物学、计算机科学和统计学。随着高通量测序技术的发展,海量的生物数据需要通过编程来进行处理和分析。因此,掌握生信编程技能,成为每一个生物信息学研究者的必备能力。 生信代码入门,旨在帮助初学者从零开始学习生物信息学中的编程基础。通过学习常用