第四周作业 wordcount 优化
GitHub 地址:
https://github.com/llag9810/Software-Quality-and-Testing-HW2
PSP2.1 表格
| PSP2.1 | PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|---|
| Planning | 计划 | 10 | 10 |
| · Estimate | · 估计这个任务需要多少时间 | 10 | 10 |
| Development | 开发 | 80 | 75 |
| · Analysis | · 需求分析 (包括学习新技术) | 5 | 5 |
| · Design Spec | · 生成设计文档 | 8 | 5 |
| · Design Review | · 设计复审 (和同事审核设计文档) | 7 | 5 |
| · Coding Standard | · 代码规范 (为目前的开发制定合适的规范) | 5 | 5 |
| · Design | · 具体设计 | 10 | 8 |
| · Coding | · 具体编码 | 10 | 12 |
| · Code Review | · 代码复审 | 15 | 15 |
| · Test | · 测试(自我测试,修改代码,提交修改) | 20 | 20 |
| Reporting | 报告 | 40 | 55 |
| · Test Report | · 测试报告 | 10 | 10 |
| · Size Measurement | · 计算工作量 | 5 | 5 |
| · Postmortem & Process Improvement Plan | · 事后总结, 并提出过程改进计划 | 25 | 30 |
| 合计 | 130 | 140 |
程序实现
本程序分为三个部分:
Main.java:程序的入口,用于读文件、完成参数有效性判断的功能。
Counter.java:计数类。用于计数,并维护计数过程中 Top100 单词。
Output.java:专用于输出的类。
程序设计思路
1. 使用正则表达式来匹配合法单词。
Pattern pattern = Pattern.compile("[A-Za-z]+(-[A-Za-z]*)?");
String line = scanner.nextLine();
Matcher matcher = pattern.matcher(line);
2. 使用 HashMap 和最小堆来维护出现频率前100的单词。
HashMap的key是单词,value是出现的次数。
单词首次出现时,加入map中。每再次扫描到这个单词,hashmap对应的value加一。然后将value和堆顶(100个元素里最小的)作比较。如果新单词的value大于堆顶,然后将新元素插入堆。如果堆的容量大于100了,那就再删掉最小元素。确保堆的容量始终是100。
while (matcher.find()) {
String s = matcher.group().toLowerCase();
if (s.endsWith("-")) {
s = s.substring(0, s.length() - 1);
}
int count = map.getOrDefault(s, 0) + 1;
map.put(s, count);
if (queue.isEmpty()) {
queue.add(s);
} else {
if (map.getOrDefault(s, 0) >= map.get(queue.peek())) {
if (queue.contains(s)) {
queue.remove(s);
}
queue.add(s);
}
if (queue.size() >= 100) {
queue.poll();
}
}
}
优先队列因为需要使用特殊的比较策略(比较map中以单词为key对应的value),所以我们需重写比较器。当两者出现次数不同时,出现次数多的即为大者。二者次数相同时,比较字典序。
queue = new PriorityQueue<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int c1 = map.getOrDefault(o1, 0);
int c2 = map.getOrDefault(o2, 0);
if (c1 - c2 != 0) {
return c1 - c2;
}
return o1.compareTo(o2);
}
});
测试设计描述
测试设计从以下几个角度来表现:
- 空用例
- 单个单词用例
- 单句子单单词用例
- 多个同句子用例
- 多个不同句子用例
- 长文本不换行用例
- 长文本用例
- 超大文件用例
| Test Case ID 测试用例编号 | Test Item 测试项(即功能模块或函数) | Test Case Title 测试用例标题 | Test Criticality重要级别 | Status 是否通过 |
|---|---|---|---|---|
| 1 | Main | BasicA | 5 | OK |
| 2 | Main | BasicB | 4 | OK |
| 3 | Main | Advanced | 4 | OK |
| 4 | Main | Special | 2 | OK |
| 5 | Counter | testm 1 | 3 | OK |
| 6 | Counter | testm 2 | 1 | OK |
| 7 | Counter | testm 3 | 5 | OK |
| 8 | Counter | testm 4 | 3 | OK |
| 9 | Counter | testm 5 | 4 | OK |
| 10 | Counter | testm 6 | 2 | OK |
| 11 | Counter | testm 7 | 5 | OK |
| 12 | Counter | testm 8 | 1 | OK |
| 13 | Counter | testm 9 | 3 | OK |
| 14 | Counter | testm 10 | 4 | OK |
| 15 | Counter | testm 11 | 5 | OK |
| 16 | Counter | testm 12 | 3 | OK |
| 17 | Counter | testm 13 | 4 | OK |
| 18 | Counter | testm 14 | 5 | OK |
| 19 | Counter | testm 15 | 3 | OK |
| 20 | Counter | testm 16 | 2 | OK |
| 21 | Counter | testm 17 | 3 | OK |
| 22 | Counter | testm 18 | 5 | OK |
| 23 | Counter | testm 19 | 5 | OK |
| 24 | Counter | testm 20 | 3 | OK |
| 25 | Counter | testl 1 | 2 | OK |
| 26 | Counter | testl 2 | 3 | OK |
| 27 | Counter | testl 3 | 4 | OK |
| 28 | Counter | testl 4 | 5 | OK |
| 29 | Counter | testl 5 | 5 | OK |
| 30 | Counter | testl 6 | 3 | OK |
| 31 | Counter | testl 7 | 3 | OK |
| 32 | Counter | testl 8 | 3 | OK |
| 33 | Counter | testl 9 | 4 | OK |
| 34 | Counter | testl 10 | 5 | OK |
| 35 | Counter | testl 11 | 5 | OK |
| 36 | Counter | testl 12 | 2 | OK |
| 37 | Counter | testl 13 | 2 | OK |
| 38 | Counter | testl 14 | 4 | OK |
| 39 | Counter | testl 15 | 1 | OK |
| 40 | Counter | testl 16 | 3 | OK |
| 41 | Counter | testl 17 | 1 | OK |
| 42 | Counter | testl 18 | 3 | OK |
| 43 | Counter | testl 19 | 4 | OK |
| 44 | Counter | testl 20 | 3 | OK |
| 45 | Counter | testz 1 | 5 | OK |
| 46 | Counter | testz 2 | 1 | OK |
| 47 | Counter | testz 3 | 2 | OK |
| 48 | Counter | testz 4 | 4 | OK |
| 49 | Counter | testz 5 | 5 | OK |
| 50 | Counter | testz 6 | 5 | OK |
| 51 | Counter | testz 7 | 2 | OK |
| 52 | Counter | testz 8 | 3 | OK |
| 53 | Counter | testz 9 | 4 | OK |
| 54 | Counter | testz 10 | 3 | OK |
| 55 | Counter | testz 11 | 4 | OK |
| 56 | Output | testz 12 | 3 | OK |
| 57 | Output | testz 13 | 5 | OK |
| 58 | Output | testz 14 | 4 | OK |
| 59 | Output | testz 15 | 3 | OK |
| 60 | Output | testz 16 | 2 | OK |
单元测试结果


评价小组成员代码
代码规范选择
使用《阿里巴巴 Java 开发手册》作为代码规范。
同行评审过程描述
作者,讲解员:朱一帆
主持人,评审员:李敏达
记录员,评审员:明煦智
评审目的
在已有的代码以及相应的代码规范基础上,我们进行代码风格以及代码质量的评审,目的有:首先是规范开发标准,确定开发的流程规范,确保开发进行过程中感到规范性。其次,遵循良好的代码规范可以让开发易于理解,便于团队合作,也利于后期维护。再者,通过评审代码,规范代码风格,提高代码质量时我们可以提高我们的代码水平,提升我们自己的工程能力,有利于我们成长为一个成熟健全的软件工程人。
经过讨论,两位评审员对于以下代码给出了评审结果是:
1. 此代码功能划分良好,按照相应的doc规范书写了比较完整的函数定义doc,但是缺少相应的行间注释,有可能造成代码的部分功能不明确。
2. 函数命名遵守了小驼峰命名,类命名遵守了大驼峰命名,语意清晰。
3. 代码冗余度小,代码风格明确,有良好的缩进习惯。
静态测试
使用 Intellij IDEA 的 lint 插件,确保命名遵循驼峰法,无拼写错误,花括号换行等没有出现问题。
性能优化
在第一个版本中,使用HashMap统计词频,然后将map里的每一项提到数组中排序,取最大的前100项作为结果。这样程序复杂度为O(nlogn)。
在目前展现在博客中的版本中,使用哈希表加最小堆的操作,假设堆中固定由k个元素,考虑最坏情况,每次都会调整堆序,程序复杂度的上界为O(nlogk)。考虑到,输入规模n可能会很大,但是在本题中,k固定为100,log2(100)可以视作一个常数。
事实上,经过本人对一些常见来源文章(例如新闻、书籍、发表文章)等的测试,Top 100的总是小部分几个常见词(The、this、do等),在大部分时间,我们是不需要调整堆序的。所以,理论上来讲平均情况应该是很接近于线性复杂度的。
另外,有考虑过用多线程去优化统计速度,不过出现了一些同步问题,所以最终版本未表现出。
小组贡献率
17055: 0.36
17066: 0.33
17057: 0.30

浙公网安备 33010602011771号