第二次作业
`| 这个作业属于哪个课程 | https://edu.cnblogs.com/campus/gdgy/SoftwareEngineeringClassof2023 |
| ----------------- |--------------- |
| 这个作业要求在哪里| https://edu.cnblogs.com/campus/gdgy/SoftwareEngineeringClassof2023/homework/13324 |
| 这个作业的目标 | <用psp查重论文> |`
我的GitHub链接:https://github.com/dio688/DIO688/tree/main/3123004277px
psp表格
| PSP阶段 | 预估耗时(分钟) | 实际耗时(分钟) |
|---|---|---|
| 计划 | ||
| 估计时间 | 480 | |
| 开发 | ||
| 需求分析 | 60 | 40 |
| 生产设计文档 | 30 | 10 |
| 设计复审 | 20 | 20 |
| 代码规范 | 20 | 40 |
| 具体设计 | 60 | 60 |
| 具体编码 | 120 | 80 |
| 代码复审 | 30 | 50 |
| 测试 | 60 | 50 |
| 报告 | ||
| 测试报告 | 30 | 30 |
| 计算工程量 | 10 | 10 |
| 事后总结与改进 | 30 | 30 |
| 总计 | 500 | 480 |
代码
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
String file1 = "orig.txt";
String file2 = "orig_add.txt";
String resultFile = "result.txt";
try {
double similarity = calculateCosineSimilarity(file1, file2);
writeResultToFile(resultFile, similarity);
System.out.println("重复率计算完成!");
} catch (IOException e) {
System.out.println("计算重复率时出现错误:" + e.getMessage());
}
}
public static double calculateCosineSimilarity(String file1, String file2) throws IOException {
// 读取文件内容
String content1 = readFileContent(file1);
String content2 = readFileContent(file2);
// 分割字符串为单词
String[] words1 = content1.split("\\s+");
String[] words2 = content2.split("\\s+");
// 计算词频向量
int[] vector1 = calculateWordFrequency(words1);
int[] vector2 = calculateWordFrequency(words2);
// 计算余弦相似度
double dotProduct = calculateDotProduct(vector1, vector2);
double magnitude1 = calculateMagnitude(vector1);
double magnitude2 = calculateMagnitude(vector2);
return dotProduct / (magnitude1 * magnitude2);
}
private static String readFileContent(String file) throws IOException {
StringBuilder content = new StringBuilder();
BufferedReader reader = new BufferedReader(new FileReader(file));
String line;
while ((line = reader.readLine()) != null) {
content.append(line).append(" ");
}
reader.close();
return content.toString();
}
private static int[] calculateWordFrequency(String[] words) {
int[] frequency = new int[words.length];
for (int i = 0; i < words.length; i++) {
frequency[i] = 1;
for (int j = i + 1; j < words.length; j++) {
if (words[i].equals(words[j])) {
frequency[i]++;
words[j] = "";
}
}
}
return frequency;
}
private static double calculateDotProduct(int[] vector1, int[] vector2) {
double dotProduct = 0;
for (int i = 0; i < vector1.length; i++) {
dotProduct += vector1[i] * vector2[i];
}
return dotProduct;
}
private static double calculateMagnitude(int[] vector) {
double magnitude = 0;
for (int value : vector) {
magnitude += Math.pow(value, 2);
}
return Math.sqrt(magnitude);
}
private static void writeResultToFile(String file, double similarity) throws IOException {
BufferedWriter writer = new BufferedWriter(new FileWriter(file));
writer.write("重复率: " + similarity);
writer.close();
}
}
结果



-
计算模块接口的设计与实现过程
代码组织
类:Main 类负责程序的入口和主要逻辑。
函数:
main:程序入口,调用计算相似度和写入结果的函数。
calculateCosineSimilarity:计算两个文件的余弦相似度。
readFileContent:读取文件内容。
calculateWordFrequency:计算词频向量。
calculateDotProduct:计算向量点积。
calculateMagnitude:计算向量模长。
writeResultToFile:将结果写入文件。
函数关系
main 调用 calculateCosineSimilarity 和 writeResultToFile。
calculateCosineSimilarity 调用 readFileContent、calculateWordFrequency、calculateDotProduct 和 calculateMagnitude。
关键函数流程图
calculateCosineSimilarity:
读取文件内容。
分割内容为单词。
计算词频向量。
计算余弦相似度。
算法关键
余弦相似度:通过计算两个向量的夹角余弦值来衡量相似度,值越接近1,相似度越高。
独到之处:直接基于词频向量计算,简单高效。
- 计算模块接口部分的性能改进
性能改进思路
优化词频计算:使用 HashMap 存储词频,减少时间复杂度。
并行处理:对大规模数据,使用多线程并行计算。
性能分析图
工具:使用 JProfiler 进行性能分析。
消耗最大函数:calculateWordFrequency,因涉及双重循环。
性能改进时间
约2小时。
- 计算模块部分单元测试展示
单元测试代码import org.junit.Test;
import static org.junit.Assert.*;
public class MainTest {
@Test
public void testCalculateCosineSimilarity() throws IOException {
String file1 = "test1.txt";
String file2 = "test2.txt";
double expected = 0.75;
double actual = Main.calculateCosineSimilarity(file1, file2);
assertEquals(expected, actual, 0.01);
}
@Test
public void testReadFileContent() throws IOException {
String file = "test.txt";
String expected = "hello world";
String actual = Main.readFileContent(file);
assertEquals(expected, actual);
}
}
测试数据构造
test1.txt 和 test2.txt:包含部分相同和不同单词的文本。
test.txt:包含简单文本。
- 计算模块部分异常处理说明
异常设计目标
IOException:处理文件读写错误。
NullPointerException:处理空文件或无效路径。
单元测试样例
@Test(expected = IOException.class)
public void testIOException() throws IOException {
Main.calculateCosineSimilarity("nonexistent.txt", "nonexistent2.txt");
}
@Test(expected = NullPointerException.class)
public void testNullPointerException() throws IOException {
Main.calculateCosineSimilarity(null, null);
}
总结
设计:代码组织清晰,函数职责明确。
性能改进:通过优化数据结构和并行处理提升性能。
单元测试:覆盖主要功能,确保代码正确性。
异常处理:处理文件读写和路径错误,增强鲁棒性。

浙公网安备 33010602011771号