• 福大软工1816 · 第二次作业


    作业说明

    github项目地址

    PSP 表格

    PSP2.1 Personal Software Process Stages 预估耗时(分钟) **实际耗时(分钟)
    Planning 计划 10 30
    · Estimate · 估计这个任务需要多少时间 480 480
    Development 开发 60 60
    · Analysis · 需求分析 (包括学习新技术) 30 180
    · Design Spec · 生成设计文档 0 0
    · Design Review · 设计复审 10 10
    · Coding Standard · 代码规范 (为目前的开发制定合适的规范) 0 0
    · Design · 具体设计 60 240
    · Coding · 具体编码 60 120
    · Code Review · 代码复审 10 10
    · Test · 测试(自我测试,修改代码,提交修改) 60 90
    Reporting 报告 20 120
    · Test Repor · 测试报告 60 120
    · Size Measurement · 计算工作量 10 120
    · Postmortem & Process Improvement Plan · 事后总结, 并提出过程改进计划 0 0
    合计 870 1580

    解题思路

    • 看到题目之后,统计词频,于是就直接打算用map去做了(因为简单方便)-但是运行速度并不是很理想
    • 然后题目涉及到了文件的读取,于是就是开始查找关于文件读写的方法
    • 接下来就是使用命令行运行exe文件以及封装,这一步是等写完整个代码之后才开始修改的,开始百度资料。

    设计过程

    • 流程图:

    • 模块划分

      • judge(string str)用来判度该串是否符合长度小于4以及首位不能为字符
      • get(string str,int &num)对每行string进行拆分
      • work(string file_name) 进行每行读取以及计算
      • output(string file_name) 用于输出
    • 最后将该模块放在一个类中

    性能分析图

    • 其中消耗最大的是work函数,毕竟这个整个程序的交汇点,进行了很多文件的读取操作
    • 其次是get函数,主要是对于每一行进行字符串拆分,由于我是用简单的string +的操作来进行,因此在速度会相对较慢。
    • 自我认为,如果把代码改成C语言的文件读取,以及把string类型修改成char 的话,会变得比较快,但是就不能用简单的map来实现了(因此就没有进行大部分优化)。

    关键代码

    • work函数
    void WordCounts::work(string file_name,string fout_name) {
    	ifstream fin(file_name, ios::in);
    	ofstream fout(fout_name, ios::out);//将 ans 写入output文件
    	int chnu = 0, words = 0, lines = 0;
    	string tmp;
    	int nucnt = 0;
    	while (getline(fin, tmp)) {
    		nucnt++;//
    		chnu += tmp.length();//字符个数记录
    		if(get(tmp, words))lines++;//分解每行字符串+判断是否为有效行数
    	}
    	si_map::iterator it;//利用迭代器遍历map
    	vector<Word>w;
    	for (it = mp.begin(); it != mp.end(); it++) {
    		Word t;
    		t.word = it->first; t.num = it->second;
    		w.push_back(t);
    	}
    	sort(w.begin(), w.end());
    	//读入output文件
    	
    	fout << "characters: " << chnu + nucnt << endl;///chun没有存取回车符
    	fout << "words: " << words << endl;
    	fout << "lines: " << lines << endl;
    	int cnt = w.size();
    	for (int i = 0; i < min(10, cnt); i++)
    	{
    		
    		fout << "<" << w[i].word << ">: " << w[i].num << endl;
    	}
    	return;
    }
    
    • get函数
    bool WordCounts::get(string str, int & num) {//对每行string进行分解+统计单词个数
    	int len = str.length();
    	int fg = 0;
    	string neword = "";
    	for (int i = 0; i < len; i++) {
    		if (str[i] != '
    ' && str[i] != ' ') fg = 1;
    		if ((str[i] > 'Z' || str[i] < 'A') && (str[i] > 'z' || str[i] < 'a') && (str[i] > '9' || str[i] < '0')) {
    			if (judge(neword)) num++;
    			neword = "";
    			continue;
    		}
    		else
    		{
    			neword += str[i];
    		}
    	}
    	if (judge(neword))num++;
    	return fg;
    }
    
    • judge函数
    bool WordCounts::judge(string str) {//判断是否符合条件+统计每个单词的出现次数
    	int len = str.length();
    	if (len < 4) return false;//长度小于4
    	if ((str[0] <= 'Z'&&str[0] >= 'A') || (str[0] <= 'z'&&str[0] >= 'a')) {//开头不能是数字
    		for (int i = 0; i < len; i++) {
    			if (str[i] <= 'Z'&&str[i] >= 'A') str[i] = str[i] - 'A' + 'a';
    		}
    		mp[str]++;//存入map
    		return true;
    	}
    	return false;
    }
    

    单元测试

    测试点 测试内容 通过情况
    in1.txt 数字不能为开头 通过
    in2.txt 有效行数 修改后通过
    in3.txt 小数据字典序排序 通过
    in4.txt 大写字母转小写 通过
    in5.txt 非字母非字符的分割 通过
    in6.txt 字母之间混杂数字的排序 通过
    in7.txt 小篇短文 通过
    in8.txt 全为数字字符和非字母字符 通过
    in9.txt 空白文件 通过
    in10.txt 字母的字典序排序 通过
    • 部分单元测试代码
    TEST_METHOD(TestMethod1)
    		{
    			// TODO: 在此输入测试代码
    			WordCounts test;
    			string fin_name = "../UnitTest1/in1.txt", fout_name = "../UnitTest1/out1.txt";
    			test.work(fin_name,fout_name);
    			test.output(fout_name);
    			ifstream fxx(fout_name, ios::in);
    			string tmp;
    			getline(fxx, tmp);
    			Assert::AreEqual((string)"characters: 16",tmp);
    			getline(fxx, tmp);
    			Assert::AreEqual(tmp, (string)"words: 1");
    			getline(fxx, tmp);
    			Assert::AreEqual(tmp, (string)"lines: 1");
    			getline(fxx, tmp);
    			Assert::AreEqual(tmp, (string)"<abcd123>: 1");
    		}
    TEST_METHOD(TestMethod3)
    		{
    			// TODO: 在此输入测试代码
    			WordCounts test;
    			string fin_name = "../UnitTest1/in3.txt", fout_name = "../UnitTest1/out3.txt";
    			test.work(fin_name, fout_name);
    			test.output(fout_name);
    			ifstream fxx(fout_name, ios::in);
    			string tmp;
    			getline(fxx, tmp);
    			Assert::AreEqual((string)"characters: 32", tmp);
    			getline(fxx, tmp);
    			Assert::AreEqual(tmp, (string)"words: 3");
    			getline(fxx, tmp);
    			Assert::AreEqual(tmp, (string)"lines: 1");
    			getline(fxx, tmp);
    			Assert::AreEqual(tmp, (string)"<windows2000>: 1");
    			getline(fxx, tmp);
    			Assert::AreEqual(tmp, (string)"<windows95>: 1");
    			getline(fxx, tmp);
    			Assert::AreEqual(tmp, (string)"<windows98>: 1");
    		}
    
    • 代码覆盖率

    • 异常处理部分

      • 主要异常是文件的读取部分,因此由以下来判断异常

    体会与收获

    • 体会:从作业布置开始,完成上面的任务,几乎已经没有心情写体会了,感觉自己做得挺崩溃的。回想起来之前每天给这个作业的时间并不多,一开始也直接胡乱写,没有认真看好设计要求,导致后面这个几个任务寸步难行。真的是像老师说的写代码的时间在整个作业的过程中是非常少的。对于我来说作业后面的性能分析、单元测试、代码覆盖率,这些基本之前没有听说过,也没有用过。在这最后两天的时间内疯狂摸索,只能说自己之前时间花得太少了,在这过程中问了一些同学,也参考了一些博客。看到提交的作业,想到为什么别人写得这么好,这么强,而我现在却是勉勉强强的把作业完成。我想每个人的差距就是在这过程中逐渐拉开的把。
    • 收获:首先,自己熟悉了git的一些操作,这次作业因为有时代码改崩了,就进行了git版本控制,真心想说 git大法好,如果没有版本控制,我基本可能就凉凉了。其次,就是VS的功能运用吧,这里的单元测试是参考 畅畅博客中的他推荐刘乾学长的博客。之后就是代码覆盖率这是参考了钧昊的在博客中提供的关于OpenCppCoverage的博客,以及钧昊博客中的使用教程。

    参考博客

    C++文件读取参考博客

    git的相关操作

    单元测试的使用

    OpenCppCoverage按装使用

    畅畅的博客

    钧昊的博客

  • 相关阅读:
    【19】网站搭建:标签功能
    【18】网站搭建:自定义用户模型
    【17】网站搭建:Celery定时刷新缓存
    【16】网站搭建:Redis缓存提速
    【15】网站搭建:用户注册登录
    【14】网站搭建:xadmin后台强化
    【13】网站搭建:全文搜索
    C#,一种简单的方式实现滚动鼠标缩放图片,平移
    WebGIS的开发方式
    C#中找不到MouseWheel事件的解决办法
  • 原文地址:https://www.cnblogs.com/q1076452761/p/9601599.html
Copyright © 2020-2023  润新知