zoukankan      html  css  js  c++  java
  • 软工第二次作业

    软工个人项目之词频统计

     

    GitHub仓库地址:https://github.com/waaaafool/081600410

    PSP 表格

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

    需求分析

    • 统计文件的字符数:
      • 只需要统计Ascii码,汉字不需考虑
      • 空格,水平制表符,换行符,均算字符
    • 统计文件的单词总数,单词:至少以4个英文字母开头,跟上字母数字符号,单词以分隔符分割,不区分大小写。
      • 英文字母: A-Z,a-z
      • 字母数字符号:A-Z, a-z,0-9
      • 分割符:空格,非字母数字符号
      • :file123是一个单词, 123file不是一个单词。file,File和FILE是同一个单词
    • 统计文件的有效行数:任何包含非空白字符的行,都需要统计。
    • 统计文件中各单词的出现次数,最终只输出频率最高的10个。频率相同的单词,优先输出字典序靠前的单词。
    • 按照字典序输出到文件result.txt:例如,windows95,windows98和windows2000同时出现时,则先输出windows2000

      • 输出的单词统一为小写格式
    • 输出的格式为

    characters: number
    words: number
    lines: number
    <word1>: number
    <word2>: number
    

    思路

    拿到题目后,进行分析,发现统计行数,输出文件,以及字母数,都只需要从文件流中读出数据,就可以进行统计。而统计单词则需要进行单词的判定,同时统计最高频率的十个单词不仅需要判定单词,还需要对单词出现的次数进行hash处理。所以就想到了,从文档流中读出string类型,然后进行分割出单词,接着则是对单词放入hash_map中,最后用遍历hash_map,放入容量为十的优先队列。最后对这剩下的十个进行按字符串的比较大小排列,输出。

    测试文档

    input

    a
    a
    a
    a
    file123

    file123
    file123
    123file
    123file
    what should i do?i donot like you.
    what should i do?i donot like you.
    what should i do?i donot like you.

    what should i do?i donot like you.

    output

    characters:190
    words: 19
    line:13
    <donot>:4
    <file123>:3
    <like>:4
    <should>:4
    <what>:4

    分析:123file不是单词,以及未满四个字符的单词均未被统计入内。空行也没被统计入行数。

    代码规范

    对于.h和.cpp文件,均使用每个单词的第一个字母大写来命名,而函数和重要变量使用驼峰法命名。

    实现

    首先确定文件的组织结构

    其中Frequency是用来统计单词的数量,而WordCount是用来统计频率最高的十个单词。

    主要算法

    统计频率最高的十个单词

    •  

    算法关键

      引入hash_map,来使查询的时间复杂度变成o(1),以及引入优先队列(堆模型),来使遍历hash_map后,储存以及更新频率最大的单词的时间变为o(lgn);

     

    编码 过程

    struct node {
    	int num;
    	string s;
    };
    node result[10];
    
    bool cmp(node a, node b) {
    	return a.s < b.s;
    }
    
    
    using namespace std;
    int number = 0;
    
    void  wordCount(const char* file){
    	ifstream fin;
    	ofstream fout;
    	fout.open("..//result.txt", ios::out | ios::app);
    	fin.open(file);
    	if (!fout) {
    		cout << "The File cannot open.1111" << endl;
    	}
    	if (!fin) {
    		cout << "The File cannot open." << endl;
    	}
    	string s;
    	hash_map<string, int> wordList;
    	while (true) {
    		fin >> s;
    		string tem="";
    		int len = s.length();
    		int pre = -1;//记录本单词上一个字母的位置,初始为-1
    
    		//进行文档流读出的string类型的单词切割
    		for (int i = 0; i < len; i++) {
    			if ('A' <= s[i]&&s[i] <= 'Z') s[i] += 32;
    			if (s[i] > 'z' || (s[i]<'a'&&s[i]>'9') || s[i] < '0') {
    				if (i - pre > 4&&(s[pre+1]<='z'&&s[pre + 1]>='a')) {
    					for (int j = pre + 1; j < i; j++)
    						tem += s[j];
    					wordList[tem]++;
    					tem = "";
    				}
    				pre = i;
    			}
    			else if (i == len - 1 && i - pre >=4 && (s[pre + 1] <= 'z'&&s[pre + 1] >= 'a')) {
    				for (int j = pre + 1; j <= i; j++)
    					tem += s[j];
    				wordList[tem]++;
    				tem = "";
    			}
    		}
    		if (fin.eof()) {
    			break;
    		}
    
    	}
    	priority_queue<pair<int, string>, vector<pair<int, string>>,greater<pair<int, string>>> maxList;
    	
    	//遍历hash_map,加入优先队列
    	for (hash_map<string, int>::const_iterator i = wordList.begin(); i != wordList.end(); i++) {
    		maxList.push(make_pair(i->second, i->first));
    		if (maxList.size() > 10) {
    			maxList.pop();
    		}
    	}
    	int i = 0;
    	//取出队列里面的值,放入result结构数组中
    	while (!maxList.empty()) {
    		result[i].num = maxList.top().first;
    		result[i].s = maxList.top().second;
    		maxList.pop();
    		i++;
    	}
    
    	//排序输出
    	sort(result, result + i, cmp);
    	for (int j = 0; j < i; j++) {
    		cout << "<" << result[j].s << ">" << ":" << result[j].num << endl;
    		fout << "<" << result[j].s << ">" << ":" << result[j].num << endl;
    	}
    	
    	fin.close();
    	fout.close();
    
    }
    

      分析:代码使用循环来分割单词,使得性能比较慢,可以改用正则表达式来改进。

    性能分析报告 

      分析:对main函数进行大量循环,发现除了那几个自己定义的函数之外,输入输出流占用的cpu比例很大,以前写一些算法题的时候也发现使用C++的输入输出流会超时。所以改用c的输入输出会好很多,因为c++的输入输出流封装了太多c的东西。

    单元测试

    设计:

    1、传入一个空文件;                              

    2、传入只有123file等的文件;

    3、传入只有空格, , 等字符;

    4、传入一个文件,其中包含空行的;

    5、传入一个文件,里面有类似adc.fef类似的非空白符为终结符的;

    6、传入一个文件,里面不超过十个有效单词的。

    7、输入一个文件,里面单词有类似window2002,window1001fa类似的,看输出排列。

    通过该变文件类型,证明成功,但由于VS未能找到对应的test,所以没有工程化测试,有点遗憾。

    代码覆盖率

    下载插件OpenCppCoverage

    代码覆盖率的截图如下:

    分析:总体而言覆盖率还是很不错的。

    异常处理

    1、在一开始进行main函数整合的时候,如果文件为空,发现会直接返回错误信息

    于是加了一个判断

    if (argv == NULL) {
    			cout << "请输入文件名" << endl;
    			return 0;
    		}
    

      

    总结和感想

    经过这次软工实践,让我感受到了为什么说退课率这么高了。很多人不一定是因为坚持不下来,而是在衡量坚持下来和换个其他东西坚持,哪个性价比更高。因为软工确实太耗时间了,真的非常耗时间。

    通过这次,最直观的就是感受到自己对各种工具的使用能力的匮乏,这次题目,编码不难,难的是在后面插件的下载与使用。

    现在想着,如果最后坚持下来,那一定能学到很多东西的。

  • 相关阅读:
    Msql-51CTO笔记
    Elasticsearch 学习第一天
    大数据开发参考资料
    1.docker的安装
    java_根据实体字段中的中文汉字排序
    遍历set集合,进行数据的拼接
    关于integer 和int
    03.linux环境安装mysql8的安装包
    02.linux下面安装jdk8
    01.VMware15.5下安装Centos7
  • 原文地址:https://www.cnblogs.com/waaaafool/p/9636865.html
Copyright © 2011-2022 走看看