软工实践寒假作业(2/2)
这个作业属于哪个课程 | 2021春软件工程实践S班 https://edu.cnblogs.com/campus/fzu/FZUSESPR21 |
---|---|
这个作业要求在哪里 | https://edu.cnblogs.com/campus/fzu/FZUSESPR21/homework/11672 |
这个作业的目标 | 1.阅读《构建之法》提问 2.WordCount编程 |
其他参考文献 | 《构建之法》CSDN |
作业基本信息 |
part1:阅读《构建之法》并提问
1.在团队合作时,如果有其中一个成员陷入了麻烦,或者没有按时完成目标,而且团队成员不在同一个地方,应该怎么有效解决?
2.敏捷开发的原则有一点是尽早并持续地交付有价值的软件以满足顾客需求,那么是和MVP的做法有什么关联吗?
思考:因为我阅读到MVP的指导思想与渐进交付相似,并且强调更早获得用户反馈。
3.敏捷流程中指出把任务分解到一个可以执行的冲刺任务,应该分解到什么程度呢?
思考:从任务的最基本的定义开始,然后在基本的定义上延展开,一步一步走。
4.敏捷流程中会遇到“认为任务都完成了”的问题,没有明确表明到底应该以何种优先级来完成那部分20%却要花80%时间的任务,按照一般开发顺序那部分20%的任务又不得不在后面才能做,那么按照作者的经验就会导致一直拖着,然后需要团队花大量的时间来解决,那有什么好的方法来解决这个问题呢?
5.MVP做法指出更早地投入到给用户反馈,如果没有获得有效地用户反馈呢?是否会影响开发?有什么好的方法获得用户反馈?
思考:因为我在想,一个产品它只有基础功能就为了让用户反馈,那么用户不一定会进行有效的反馈,那么到最后不也是和渐进交付流程是一样的,当最终产品出来时才有获得真正地反馈,
part2:WordCount编程
1.Github项目地址
https://github.com/Zhengkaixin/PersonalProject-C.git
2.PSP表格
PSP2.1 | Personal Software Process Stages | 预估耗时(分钟) | 实际耗时(分钟) |
---|---|---|---|
Planning | 计划 | ||
• Estimate | • 估计这个任务需要多少时间 | 300 | 250 |
Development | 开发 | 690 | 1040 |
• Analysis | • 需求分析 (包括学习新技术) | 30 | 40 |
• Design Spec | • 生成设计文档 | 20 | 30 |
• Design Review | • 设计复审 | 30 | 50 |
• Coding Standard | • 代码规范 (为目前的开发制定合适的规范) | 30 | 30 |
• Design | • 具体设计 | 40 | 50 |
• Coding | • 具体编码 | 320 | 480 |
• Code Review | • 代码复审 | 120 | 240 |
• Test | • 测试(自我测试,修改代码,提交修改) | 60 | 120 |
Reporting | 报告 | ||
• Test Repor | • 测试报告 | 30 | 20 |
• Size Measurement | • 计算工作量 | 30 | 30 |
• Postmortem & Process Improvement Plan | • 事后总结, 并提出过程改进计划 | 60 | 90 |
合计 | 1110 | 1430 |
3.解题思路描述
一开始看到编程作业,觉得看起来有点复杂,然后开始静下来考虑怎么做。
①统计字符数,就简单的使用条件语句判断是否为ascii码;
②统计单词总数,就按照要求先进行分割,然后在统计符合要求的单词(一开始没有细想,后来编程遇到了一些逻辑问题);
③统计有效行数,也是简单地判断是否存在非空白字符的行;
④统计并输出频率最高的10个单词,一开始想在统计单词总数的基础上,可以使用自定义类来保存符合的单词,然后在进行遍历统计出现的次数,最后排序输出。
4.代码规范制定链接
https://github.com/Zhengkaixin/PersonalProject-C/blob/main/221801319/src/README.md
5.设计与实现过程
5.1.1 开始设计时,将每个功能分别作为一个类,然后自定义一个类用来保存符合条件的单词,预计有5个类。
5.1.2 在每个类中,设计相应的统计函数,同时在输出频率最高的10个单词的类中,设计一个排序函数。同时,封装各个类的数据,用set和get函数进行操作。
5.1.3 发现统计并输出频率最高的10个单词,可以使用到前面统计单词总数所得到的数据,用其所获得的数据来确定用来保存单词的对象的个数,创建一个对象数组。
5.2.1 开始实现的时候,创建5个类,放在5个头文件中
my_word类 用来存储单词,以及记录单词出现的次数;
repeatCount类 用来寻找频率最多的10个单词,并进行排序按字典序输出;
rowCount类 用来进行有效行的统计;
wordCount类 用来进行单词数目的统计,得到的数目可以作为创建my_word类对象数组的空间大小;
charCount类 用来进行字符数量的统计。
5.2.2 在实现过程中,我认为逻辑比较复杂的有两个地方
①如何得出10个频率最高的单词。
我的思路是:先将所有出现的单词都保存下来,并统计其出现的频率;然后通过比较频率得到10个最高频率的单词,将这些单词用向量类保存并排序,最后输出符合要求的单词序列。在比较频率时,我用的是遍历一次my_word类对象数组寻找最高频率,在遍历寻找次高频率,如此重复找到10个,这样就可以将时间复杂度降低到o(n)。
for (int j = 0;j < number;j++) {
if (myword[j].getFreque() > max) {
max = myword[j].getFreque();
num[0] = j;
}
}
实现逻辑复杂在于:
**例如最高频率的单词,频率一样且有11个,那么就应该全部获取这11个单词,但是第一次遍历获得了一个最高频率,那么接下来还可能存在一样高的,所以就要再设计一次遍历,将所有相同频率的单词全部找出来,同时如果计算此时单词数如果已经超过10个就可以跳出循环;
**同时如果最高的和次高的单词数都是多个的话,他们就要各自先进行排序
for (int i = 1;i < number;i++) {
v_sort.push_back(myword[num[i - 1]].getStr());
max_len = i;
for (int j = 0;j < number;j++) {
if (myword[j].getFreque() == max && j!=num[i-1]) {
num[i] = j;
i++;
}
}
if (i > max_len) {
for (int a = max_len;a < i;a++) {
v_sort.push_back(myword[num[a]].getStr());
}
sort(v_sort.begin(), v_sort.end());
for (it = v_sort.begin();it != v_sort.end();it++) {
v.push_back(*it);
}
v_sort.clear();
}
else {
it = v_sort.begin();
v.push_back(*it);
v_sort.clear();
}
②如何确定符合条件的单词
首先任何非字母和数字都可以作为分隔符,我查阅资料有没有什么可以方便分割的方法,没有查到,于是我就开始思考。
——我使用getline直接获取一行,开始我觉得直接判断有四个连续字母的就可以作为单词,简单的作为条件判断
——之后发现如果一行内的字符串内部会含有多个分隔符,那么可能就是多个单词。于是我设置了一个标志,用来标记分隔符,当遇到分隔符时标记变为true,开始作为一个新的单词的开始,用tmp_1来计算字母数量,当遇到数字时,且tmp_1小于4,那么将标记改为false,并tmp_1值变为0,等待遇到下一个分隔符然后在进行统计。
void wordcount(fstream &inputFile) {
//string str;
char data[256];
int tmp = 0;
int tmp_1 = 0;//统计单词开头字母个数
bool flag = true;//标志分隔符
while (inputFile.getline(data,256) ){
for (int i = 0;i < strlen(data);i++) {
if (isalpha(data[i])) {
data[i]=tolower(data[i]);
}//全部转换为小写
if ((data[i] >= 'a' && data[i] <= 'z') || (data[i] >= 'A' && data[i] <= 'Z')) {
if (flag) {
tmp_1++;
}
}
else if ((data[i] >= '0' && data[i] <= '9')&&tmp_1 < 4) {
tmp_1 = 0;
flag = false;
}
else if (!((data[i] >= 'a' && data[i] <= 'z') ||/* (data[i] >= 'A' && data[i] <= 'Z') ||*/ (data[i] >= '0' && data[i] <= '9'))) {
flag = true;
if (tmp_1 < 4) {
tmp_1 = 0;
}
else {
tmp_1 = 0;
tmp++;
}
}
}
if (tmp_1 >= 4) {
tmp++;
tmp_1 = 0;
}
}
setNumber(tmp);
}
6.性能改进
在进行统计单词频率,寻找最多的10个单词时,一开始想要用最简单但是复杂度为o(n2)的冒泡排序,后来发现就直接寻找前10个最多的就可以了,就把复杂度降低到了o(n)
7.单元测试
8.异常处理说明
源文件main函数打开文件时,判断能否成功打开,不能打开,提示并退出程序。
stream.open("argv[1]", ios::in);
if (!stream) {
cout << "fail to open" << endl;
return -1;
}
9.心路历程与收获
①尝试使用github来上传代码,并和同学交流一些问题,重拾了c++的一些知识;
②尝试进行了单元测试和性能测试;
③发现养成良好的代码规范习惯有助于在重新梳理代码逻辑时,更快的找到思路;
④要加强写代码之前的设计,不能草率的觉得需求很简单,这次在写代码时就因为开始设计的时候很多问题没想清楚,导致写代码时在逻辑问题上卡了很久。