zoukankan      html  css  js  c++  java
  • 2018软件工程第二次作业——个人项目

    1.WordCount项目031602510/scr

    2.psp表格

    PSP2.1 Personal Software Process Stages 预估耗时(分钟) 实际耗时(分钟)
    Planning 计划 80 60
    · Estimate · 估计这个任务需要多少时间 80 60
    Development 开发 2000 2700
    · Analysis · 需求分析 (包括学习新技术) 400 450
    · Design Spec · 生成设计文档 30 50
    · Design Review · 设计复审 30 60
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范) 60 60
    · Design · 具体设计 150 180
    · Coding · 具体编码 1000 1300
    · Code Review · 代码复审 60 60
    · Test · 测试(自我测试,修改代码,提交修改) 280 370
    Reporting 报告 90 120
    · Test Repor · 测试报告 60 90
    · Size Measurement · 计算工作量 30 30
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 实际用的时间会比起估计时间长上许多 所以应该安排好时间提前几天完成任务,不然会造成最后几天疯狂赶代码的情况

    3.解题思路描述。即刚开始拿到题目后,如何思考,如何找资料的过程。

    解题思路:仔细阅读作业题目之后,发现程序要完成四件任务:

    • <1>统计文件的字符数
      • 只需要统计Ascii码,汉字不需考虑
      • 空格,水平制表符,换行符,均算字符

    估摸着应该是可以用函数fopen()来打开文件,然后用 fgetc()来逐个获取文件中的字符,这个应该不难实现,不过写出来的代码才发现提示fopen()是unsafe的,查了资料才知道现在都建议用函数fopen_s(),二者在接受参数返回值上都有区别。

    • <2>统计文件的单词总数,单词:至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。

      • 英文字母: A-Z,a-z
      • 字母数字符号:A-Z, a-z,0-9
      • 分割符:空格,非字母数字符号

    一开始没有看清楚后面的单词实例,一开始感觉要求有歧义,走了很多弯路。对于单词总数的统计,我的思路是先将输入的input.txt文件存入一个字符串变量之中,然后对字符串进行预处理———大写转化为小写,除英文字母,数字以外的字符统一用空格符号代替,然后将字符串按空格隔开放进unordered_map<string, int> strMap;中,最后用容器vector和定义的sort();生成字典排序,然后遍历将符合条件的单词个数累加。

    • <3>统计文件的有效行数:任何包含非空白字符的行,都需要统计。

    行数的统计虽然会稍微简单点,不过也有一些坑点,比如空白行可能存在着空格不只有" ",我写的程序一开始嗨啊忽略了第一行是空白的情况,多次测试之后才发现问题;

    • <4>统计文件中各单词的出现次数,最终只输出频率最高的10个。频率相同的单词,优先输出字典序靠前的单词。

      • 按照字典序输出到文件result.txt:例如,windows95,windows98和windows2000同时出现时,则先输出windows2000
      • 输出的单词统一为小写格式

    一开始把result.txt文件忘了,后来经过舍友提醒才知道的,关于单词频率的统计思路和之前写的单词数统计的主要思想差不多,不过统计的是字典序的单词,不过今天思考了一下比起用sort()函数,用堆排序单词会更快,还有听说有的同学遍历了十次容器每次取出最小的字典序单词,只需要O(10N),可以说是很黑科技了。

    4.设计实现过程。设计包括代码如何组织,比如会有几个类,几个函数,他们之间关系如何,关键函数是否需要画出流程图?单元测试是怎么设计的?

    设计的实现过程:
    类图

    流程图

    单元测试的设计,
    其实总共有十个测试的,就不一一列出来了

    text.cpp
    
    #include "stdafx.h"
    #include "CppUnitTest.h"
    #include "../WordCount/stdafx.h"
    
    using namespace Microsoft::VisualStudio::CppUnitTestFramework;
    
    namespace UnitTest1
    {		
    	TEST_CLASS(UnitTest1)
    	{
    	public:
    		
    		TEST_METHOD(TestMethod1)
    		{
    			int Charnum = 198;//期望的测试结果
    			int WordNum = 7;
    			int lineNum = 3;
    			char* filename = "F:\WordCount\UnitTest1\test.txt";//文件存放位置绝对路径
    			FILE *fp;
    			fopen_s(&fp, filename, "r");
    			WordCount A(fp, filename);
    			Assert::AreEqual(lineNum, A.LineCount());//用的函数接口作为参数做测试
    			Assert::AreEqual(Charnum, A.CharCount());
    			Assert::AreEqual(WordNum , A.WordNum());
    		}
    	};
    
    }	
    	
    

    测试结果查看

    5.记录在改进程序性能上所花费的时间,描述你改进的思路,并展示一张性能分析图(由VS2017的性能分析工具自动生成),并展示你程序中消耗最大的函数。

    cpu占用图

    main函数占用

    占用最大的操作原来和vector有关

    代码覆盖率

    改进思路,对于容器vector和排序sort()是可以找到更好的替代,用堆排序或者遍历10次Map应该会减少算法复杂度。

    6.代码说明。展示出项目关键代码,并解释思路与注释说明。

    下面就是自己觉得花了比较多时间的核心代码:主要是单词以及频率输出部分,其他就不做赘述。

    unordered_map<string, int> strMap;
    
    
    bool mysort(pair < int, string > a, pair < int, string > b)//定义sort规则
    {
    	if (a.first != b.first)
    		return a.first > b.first;
    	else
    		return a.second < b.second;
    }
    
    
    void GetMap(stringstream &ss)//生成string中单词的键值对
    {
    	string strTmp;
    	while (ss >> strTmp)
    	{
    		unordered_map<string, int>::iterator it = strMap.find(strTmp);
    		if (it == strMap.end())
    		{
    			strMap.insert(unordered_map<string, int>::value_type(strTmp, 1));
    		}
    		else
    			strMap[strTmp]++;
    	}
    }
    
    
    void WordCount::LetterCount() //字符统计函数
    {
    	string strFile, tmp;
    	int i = 0;
    	ifstream file(target_file);      //读取当前文件夹下input.txt文件
    	while (getline(file, tmp))//直到文件结尾,依次逐行读入文本
    	{
    		strFile.append(tmp); //每次读入一行附加到strFile结尾
    		strFile.append(" ");//行尾补充空格
    		tmp.clear();            //记得清除,否则上一次读入比这次文本长,不会完全覆盖而出错
    	}
    	for (unsigned int i = 1; i <= strFile.size(); i++)//将字符串中英文字母大写转小写
    	{
    
    		if (strFile[i] >= 'A'&&strFile[i] <= 'Z')
    			strFile[i] += 32;
    	}
    	for (unsigned int i = 0; i < strFile.length(); i++)//分隔符号替换成为空格
    	{
    		if (ispunct(strFile[i]))
    			strFile[i] = ' '; 
    	}
    	stringstream ss(strFile);
    	if (strMap.empty()) GetMap(ss);
    	
    	vector < pair < int, string > > m;//容器
    	for (unordered_map<string, int>::iterator it = strMap.begin(); it != strMap.end(); ++it)
    		m.push_back(make_pair(it->second, it->first));
    	sort(m.begin(), m.end(), mysort);//排序
    	for (unsigned int k = 0; k < m.size(); ++k)//输出单词以及频率
    	{
    		string a = m[k].second.c_str();
    		if (
    			((a[0] >= 'a'&&a[0] <= 'z') || (a[0] >= 'A'&&a[0] <= 'Z')) &&
    			((a[1] >= 'a'&&a[1] <= 'z') || (a[1] >= 'A'&&a[1] <= 'Z')) &&
    			((a[2] >= 'a'&&a[2] <= 'z') || (a[2] >= 'A'&&a[2] <= 'Z')) &&
    			((a[3] >= 'a'&&a[3] <= 'z') || (a[3] >= 'A'&&a[3] <= 'Z')))
    		{
    			cout << '<' << a << '>' << ":" << m[k].first << endl;//打印结果
    			i++;
    			if (i >= 10)//输出频率前十
    				break;
    		}
    	}
    }
    
    

    7.结合在构建之法中学习到的相关内容与个人项目的实践经历,撰写解决项目的心路历程与收获。

    一开始并没有感觉第二次作业会很难,git的操作之前有过,都蛮顺利的,写代码也没有花费很多时间。看到题目之后捋了一下思路,其实题目就是在之前c/c++课程的基础上,把一个个简单的功能糅合成一个程序,往里面掺杂一些文件的读写,排序,字符串处理等一些“简单”操作,应该不难。

    但是当调试的时候,和同学一对比运行结果,就发现不少问题,代码有很多bug导致结果出错,主要还是没有考虑周全,有的地方代码不得不重新写过,用到Map和容器的时候,由于不熟悉,甚至结果完全出错,在电脑面前找了一个多小时,最后发现是自己写的Get Map()(往Map里面传数据的函数)多次传入,导致单词频率的统计结果翻了几倍。

    接下来就是单元测试?什么是单元测试??怎么测试???这是第一次听的时候的心理活动,不过万能的百度和善良的同学给了我不少帮助,最后也学会了编写测试代码,看测试结果是否正确。期间还有一个小插曲,写好测试程序之后不管怎么测试,都会有部分通过不了,但是运行结果是没错的?!自己折腾了一两个小时,查Assert::AreEqual()的很多资料,感觉测试结果不应该不对啊,然后舍友说,你再运行一下未通过的测试,然后居然能通过了。

    最后对于封装,也是一知半解,感觉封装的也不是很完善,第一次认真正式地封装。

    现在对于这次的作业,感觉就是各种触及我的知识盲区,不过有所得。说实话,和周围同学比起来,作业对于我来说是挺吃力的,甚至于过程是艰难的,不过能听听同学聊聊程序的改进,向他们学习,上网络上查资料,自己也把查资料过程中的好博客和内容摘抄下来,积累起来,也有欣慰。

  • 相关阅读:
    linux设备驱动归纳总结(六):3.中断的上半部和下半部——tasklet【转】
    linux设备驱动归纳总结(六):2.分享中断号【转】
    linux设备驱动归纳总结(六):1.中断的实现【转】
    linux设备驱动归纳总结(五):4.写个简单的LED驱动【转】
    linux设备驱动归纳总结(五):3.操作硬件——IO静态映射【转】
    【转】浮点型转换整型的快速方法介绍--不错
    【转】单双精度浮点数的IEEE标准格式
    【转】android ddms中查看线程释疑
    【转】android中如何查看某个线程的logcat--不错
    【转】android:DDMS查看Threads--不错
  • 原文地址:https://www.cnblogs.com/dalegac/p/9631924.html
Copyright © 2011-2022 走看看