欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

软件工程实践2018第二次作业——个人项目

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

解题思路

对于这个题目来说读取字符数和行数是基本操作,题目的难点在于按照给定规则对文本进行划词,以及在单词数量大时如何保证词频查找更新的空间复杂度,一开始时我想直接使用标准模板库中的map来进行单词频率的存储,但后来查看其底层实现时发现C++的map是基于BST实现的。虽然每次查找有O(logN)的时间复杂度,但当单词数量大时,时间复杂度依然太高,后来在 畅畅 同学的提醒下,我使用基于哈希实现的unordered_map来存储单词及其词频,通过牺牲空间复杂度换取每次查找O(1)的时间复杂度。

接口设计与实现过程

需求分析:

  • 读取txt文件中内容(基础功能)

  • 统计文件的字符数(基础功能)

  • 统计文件的单词总数(基础功能)

  • 统计文件的有效行数(基础功能)

  • 统计文中的各单词的出现次数,最终输出频率最高的10个(拓展功能)

  • 接口封装(拓展功能)

实现过程

程序基本框架:根据需求分析我将整个程序划分为5个主体部分

  • 文件读取与接口调用部分

  • 字符数统计部分

  • 行数统计部分

  • 单词统计部分

  • 单词词频统计部分

接口设计:

  • 字符数统计部分:int CountChar(char *filename)
  • 行数统计部分:int CountLine(char *filename)
  • 单词统计部分:int CountAllWords(char *filename)
  • 词频统计部分:vector<pair<string, int>> top10words(char *filename)

各部分实现:

  • 文件读取实现:通过使用C++的fstream类读取文件流
  • 字符数统计部分:每次从文件流中读取一个字符并计数
  • 行数统计部分:运用C++的getline函数从fstream对象中按行读取并计数
  • 单词统计部分:首先需要按照规则划分出每个单词,其次对每个单词进行计数
    • 划分单词:根据C++ fstream类的get()方法在按string读取时会自动按空格划分的特点,首先读入由空格划分的字符串,在此基础上需要对这个字符串内部再进行切分比如出现‘hello,world’时,程序应该准确讲此字符串划分为‘hello’和‘world’,我采用的方法是通过遍历字符串,并设置is_head,not_a_word两个flag来完成string内划词的操作
    • 流程图
      软件工程实践2018第二次作业——个人项目
    • 核心代码
      软件工程实践2018第二次作业——个人项目
  • 单词词频top10:使用基于priority_queue实现的小顶堆来维护top10词频队列,当队列中元素不足十个时直接入队,当队列中满时,对栈顶元素与欲入队元素进行比较,首先比较词频,词频相同比较字典序
    • 流程图
      软件工程实践2018第二次作业——个人项目
    • 核心代码
      软件工程实践2018第二次作业——个人项目

性能分析及改进

在性能分析中我循环执行如下文本1000000次

h
e
l
l
o
hello
hello123
123hello
  hello
HELLO
123file

软件工程实践2018第二次作业——个人项目

软件工程实践2018第二次作业——个人项目

软件工程实践2018第二次作业——个人项目

可以发现性能瓶颈主要出现在文件读取以及删除空格单词的词频上,通过代码逻辑优化后,执行同样的测试,运行时间缩短了3秒

软件工程实践2018第二次作业——个人项目

单元测试改进

十个单元测试

  • 文本不存在

  • 无参数输入

  • 空文本

  • 单词以数字开头

  • 大小写单词

  • 其他字符

  • 单词长度

  • 参数超过限制

  • 文本包含10个以上的不同单词

  • 文本只包含空格、换行符与制表符

  • 10个测试通过

软件工程实践2018第二次作业——个人项目

代码覆盖率

软件工程实践2018第二次作业——个人项目

代码覆盖率低的filedetect.cpp,是因为没被覆盖的代码是应对错误参数输入设计的

异常处理说明

  • 针对参数输入错误的异常处理:
    • 当无文本参数输入时
    • 当输入参数过多时
    • 文本文件不存或无法打开时

软件工程实践2018第二次作业——个人项目

  • 针对空文本输入时,防止优先队列容量为0时的访问越界情况:

软件工程实践2018第二次作业——个人项目

心得体会

  • 通过这次个人项目,我逐步开始体会到软件工程这门课程的重要性,以前写一些大点的程序,在代码改动时整个项目就像倒过来的金字塔,改动任何一处都会导致一连串错误的发生。在这次实践中我按照PSP表格对项目的规划一步一步地完成了整个项目,而不像从前为了尽快完成作业,用一种写了再说的方式来对待项目。这种步步为营的计划也许就是软件工程中“工程”二字的含义所在吧。毫无疑问,按照这种方式写出的软件结构性更强,而且各个模块也能包产到户,使得项目进展更容易衡量。

  • 针对PSP表格中的结果,我对自己的时间预计出现了很大偏差,特别是测试部分的时间预估远远不足,这和我对单元测试的认识有很大关系,相信随着之后的学习,对项目的时间规划会越来越趋于实际

  • 以前对github以及git的认识一直停留在纸面上,虽然知道它们是coder强大的工具,但一直觉得自己写小项目用github有大材小用的感觉,直到这次在项目进行时全程按照规范,一旦项目进展立刻签入github,我才对github有了真正可感的认识。在实现业务逻辑时不用畏手畏脚的感觉实在太棒了。

  • 此外这也是第一次为自己写的软件写单元测试,终与知道还有这样相对轻松且自动化的测试方式