软工实践第二次作业2.0

github地址

anmui

PSP表格

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

计算模块接口的设计与实现过程。

  • 定义了四个函数体头文件。

  • 各个接口间独立,分别向文件中输入结果。

  • 算法的关键在于建立map,key是单词,value是出现次数。

  • 在统计频率时,原本想的是记下来每个单词出现的频率后再排序,这样会用到O(N*log N)。在查阅一些资料后,后来才发现可以直接保存频率最高的几个单词,遍历的同时替换就可以了,降到了O(N)。下图为排序过程


###性能改进

(1)
输入改进,具体见1.0版。

(2)

  • 因为算法是统计单词用的是链表,所以插入单词时要遍历整个链表,随着单词数的增加,要遍历的链表越来越长。当运行200万字数的文档是,结果一直跑不出来。

  • 于是我想到了第一种改进策略,链表一开始插入的时候不找相同的单词,建立一个首字母链表,记录每个首字母单词的位置,插入到首字母相同的单词后,如果该单词的首字母没有在首字母链表中,就将该单词插入在首字母链表中。这样首字母链表最多有26个节点。如果一个单词要插入到链表中最多遍历26遍。这样就是把所有单词加入到了链表中,之后就是将相同的单词合并,这样一个单词就不用遍历整个链表找自己的相同的单词,只需要在与自己首字母相同的范围寻找就行了。这样运行200万字的文档就能跑出来了,但是要45秒。(具体代码可看github注释部分)

  • 尽管相同单词合并时时间减小,但是仍要遍历与自己首字母相同的单词链表,耗时o(n!),显然耗时太久了。在与同学的交流中,知道了map这种方便的存在,他用红黑二叉树,插入时间会大大变短。于是我去学了下map的使用。就把链表改成了map,运行时间果然变短了,运行200万字的文档要20s左右。

单元测试

单元测试结果

展示测试求字符总数的函数的单元测试代码

#include "stdafx.h"
#include "CppUnitTest.h"
#include"../wordCount/readchars.h"
#include"../wordCount/readlines.h"
#include"../wordCount/readword.h"
#include"../wordCount/sort.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace UnitTest2
{		
	

	TEST_CLASS(UnitTest2)
	{
	public:
		
		TEST_METHOD(TestChars)//测试字符数函数
		{
			// TODO: 在此输入测试代码
			string filename = "C:/Users/Mac/Desktop/1234.txt";
			int file_chars = 0;
			Assert::AreEqual(0, readchars(filename, file_chars));
		}
}

思路:如果可以正确打开文件并且成功运行会返回0,测试该模块是否与0相等,附上读取字符数的代码。

#include"pch.h"
#include"readchars.h"
#include"structword.h"
#include<fstream>
using namespace std;


/**********************读取字符*********************/
int readchars(string filename, int file_chars)
{
	ifstream file(filename);
	//FILE *file = _fsopen(filename, "r", _SH_DENYNO);
	if (!file)
	{
		printf( "打开文件错误!" );
		return 0;
	}
	char chars = -1;
	while (1)
	{
		//chars = fgetc(file);
		chars = file.get();
		if (chars == EOF)
			break;
		file_chars++;
	}
	std::ofstream openfile("result.txt", std::ios::trunc);
	openfile << "characters: " << file_chars << endl;
	openfile.close();
	return 0;
}

单元测试测试覆盖率


异常处理模块

异常处理:
路径无效时显示无法打开文件并退出

    ifstream file(filename);
	if (!file)
	{
		printf( "打开文件错误!" );
		return 0;
	}

单元测试

TEST_CLASS(UnitTest2)
	{
	public:
		
		TEST_METHOD(TestChars)
		{
			// TODO: 在此输入测试代码
			string filename = "mm";
			int file_chars = 0;
			Assert::AreEqual(0, readchars( filename, file_chars));
		}

filename为无效地址

结果通过测试

总结

我用了很长的时间来做这次作业,在这次作业的过程中遇到了很多困难也学到了很多知识。通过这次学习我知道了以后可以通过单元测试来增加代码的可靠性,也知道了如何将函数封装成头文件。遇到的困难有些已经解决,有些还需要继续深入研究。写这个程序我也没有用到特别复杂的算法,在与其他同学交流解题思路的过程中,我深刻的意识到了自己的不足以及与别人的差距。以后,我一定丰富自己的知识,将之前那些看不懂就放到一边的算法拾起来。

学习记录

学习c++ofstream和ifstream

问题

(1)vs2017无法查找或打开 pdb 文件
(2)单元测试方法1单元测试方法2
(3)C语言中 scanf_s和 scanf 区别
C++中函数strcpy和strcpy_s
(4)C如何在一个文件里调用另一个源文件中的函数
(5)struct重定义//重复包含头文件
(6)性能分析报告与性能优化
(7)看代码覆盖率使用OpenCppCoverage插件
(8)map学习

posted @ 2018-09-20 09:16  anmui  阅读(152)  评论(2编辑  收藏  举报