第4周作业:WordCount 优化
1. GitHub地址
https://github.com/llag9810/Software-Quality-and-Testing-HW2
2. PSP表格
| PSP阶段 | 预计耗时(分钟) | 实际耗时(分钟) |
| 计划 | 2h | 1h |
| .估计这个任务需要时间 | 5h | 3h |
| 开发 | 8h | 8h |
| .需求分析(包括学习新技术) | 1h | 1h |
| .生成设计文档 | 1.5h | 1.5h |
| .设计复审 | 0.5h | 0.5h |
| .代码规范 | 1h | 1h |
| .具体设计 | 0.5h | 0.5h |
| .具体编码 | 2h | 2h |
| .代码复审 | 1 | 1h |
| .测试 | 1h | 1h |
| 报告 | 2h | 2h |
| .测试报告 | 0.5h | 0.5h |
| .计算工作量 | 0.2h | 0.2h |
| .事后总结并提出改进计划 | 0.3h |
0.3h |
| 合计 | 10h |
10h |
3. 代码实现
本程序分为三个部分:
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); } });
3. 测试用例
见下图
| 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 |
4. 单元测试结果


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

浙公网安备 33010602011771号