第一次个人编程作业

这个作业属于哪个课程 班级的链接
这个作业要求在哪里 作业要求的链接
这个作业的目标 完成论文查重程序

github仓库地址:

https://github.com/Xb2555/Xb2555

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

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

  1. 代码组织

    • 分词模块:将输入的文本分词。
    • 向量构建模块:将分词结果转换为词频向量。
    • 相似度计算模块:基于词频向量计算余弦相似度。
  2. 类与函数设计

    • Main 类:包含主程序逻辑和核心方法。
    • JiebaSegmenter 类:第三方分词工具类(来自 jieba-analysis 库)。
    • calculateCosineSimilarity:计算两个文本的余弦相似度。
    • segmentWords:对文本进行分词。
    • buildVector:构建词频向量。
  3. 函数之间关系

    • calculateCosineSimilarity 是核心函数,负责调用其他函数完成以下任务:
      • 调用 segmentWords 对输入文本进行分词。
      • 调用 buildVector 构建词频向量。
      • 计算余弦相似度并返回结果。
    • segmentWords 依赖于 JiebaSegmenter 进行分词。
    • buildVector 将分词结果转换为词频向量,供 calculateCosineSimilarity 使用。
  4. 算法关键点

    • 分词

      • 使用 JiebaSegmenter 对中文文本进行分词。
        分词结果是一个词语列表,例如:
        输入:"我爱北京天安门"
        输出:["我", "爱", "北京", "天安门"]
    • 词频向量构建

      • 使用一个 Map<String, int[]> 来存储词频向量。
        Key:词语。
        Value:一个长度为 2 的数组,分别表示两个文本中该词语的频率。
    • 余弦相似度计算

      • 计算步骤:
        1. 计算点积:dotProduct = sum(A_i * B_i)。
        2. 计算向量的模长:norm1 = sqrt(sum(A_i^2)),norm2 = sqrt(sum(B_i^2))。
        3. 计算相似度:dotProduct / (norm1 * norm2)。
  5. 独到之处

    • 中文分词的支持

    • 使用 JiebaSegmenter 对中文文本进行分词,能够准确处理中文词语的切分问题。

    • 分词结果转换为小写,避免大小写对相似度计算的影响。

    • 词频向量的高效构建

      • 使用 Map<String, int[]> 存储词频向量,避免了稀疏向量的存储问题。
      • 通过一次遍历即可完成两个文本的词频统计,时间复杂度为 O(n)O(n),其中n 是词语总数。
    • 余弦相似度的高效计算

      • 通过一次遍历词频向量,同时计算点积和模长,避免了多次遍历。
        -处理了分母为零的情况,避免除零错误。
    • 模块化设计

      • 将分词、向量构建、相似度计算分离为独立的函数,便于扩展和维护。
      • 例如,如果需要支持英文文本,可以替换分词模块,而不影响其他部分的逻辑。

计算模块接口部分的性能改进

  1. 性能分析

    • 分词阶段
      • 使用 JiebaSegmenter 对两个文本进行分词。
      • 分词时间复杂度为O(n),n为文本长度
      • 假设两个文本的长度分别为n1和n2,则分词阶段总时间复杂度为O(n1+n2)
    • 向量构建阶段
      • 遍历两个分词结果列表,构建词频向量。
      • 假设两个文本的分词结果总数为m,则构建词频向量的时间复杂度为O(m)
    • 相似度计算阶段
      • 遍历词频向量,计算点积和模长。
      • 假设词频向量的大小为k,则计算相似度的时间复杂度为O(k)
  2. 改进思路

    • 高效处理中文分词
      • 使用 JiebaSegmenter:
      • Jieba 是中文分词领域广泛使用的工具,分词准确且性能较好。
      • 分词结果转换为小写,避免大小写对相似度计算的影响。
    • 词频向量的高效构建
      • 使用 Map<String, int[]> 存储词频向量:
      • 通过哈希表存储词频,避免了稀疏向量的存储问题。
      • 一次遍历即可完成两个文本的词频统计,时间复杂度为O(m)

计算模块部分单元测试展示

  1. 测试 segmentWords 方法:
    • 准备一段中文文本。
    • 调用 segmentWords 方法进行分词。
    • 验证分词结果是否符合预期。
// 中文分词
    //测试中文分词函数
    @Test
    public void testSegmentWords() {
        JiebaSegmenter segmenter = new JiebaSegmenter();
        String text = "我爱软件工程";
        List<String> words = Main.segmentWords(segmenter, text);

        // 验证分词结果
        List<String> expected = Arrays.asList("我", "爱", "软件工程");
        assertEquals(expected, words);
    }
  1. 测试 calculateCosineSimilarity 方法:
    • 准备两段中文文本。
    • 调用 calculateCosineSimilarity 方法计算相似度。
    • 验证计算结果是否在合理范围内。
//测试计算余弦相似度函数
    @Test
    public void testBuildVector() {
        List<String> words1 = Arrays.asList("apple", "banana", "apple");
        List<String> words2 = Arrays.asList("banana", "orange", "banana");
        Map<String, int[]> vectorMap = new HashMap<>();
        Main.buildVector(words1, vectorMap, 0);
        Main.buildVector(words2, vectorMap, 1);

        // 验证词频向量
        assertArrayEquals(new int[]{2, 0}, vectorMap.get("apple"));
        assertArrayEquals(new int[]{1, 2}, vectorMap.get("banana"));
        assertArrayEquals(new int[]{0, 1}, vectorMap.get("orange"));
    }
  1. 测试 main 方法:
    • 模拟命令行参数。
    • 创建临时文件作为输入和输出文件。
    • 调用 main 方法。
    • 验证输出文件中的内容是否符合预期。
//测试命令行输入及输出
    @Test
    public void testMain(@TempDir Path tempDir) throws IOException {
        // 创建临时文件
        File originalFile = tempDir.resolve("original.txt").toFile();
        File plagiarizedFile = tempDir.resolve("plagiarized.txt").toFile();
        File outputFile = tempDir.resolve("output.txt").toFile();

        try (BufferedWriter writer = new BufferedWriter(new FileWriter(originalFile))) {
            writer.write("我爱北京天安门");
        }
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(plagiarizedFile))) {
            writer.write("我爱北京天安门");
        }

        // 模拟命令行参数
        String[] args = new String[]{
                originalFile.getAbsolutePath(),
                plagiarizedFile.getAbsolutePath(),
                outputFile.getAbsolutePath()
        };

        // 调用 main 方法
        Main.main(args);

        // 验证输出文件内容
        try (BufferedReader reader = new BufferedReader(new FileReader(outputFile))) {
            String result = reader.readLine();
            assertEquals("100.00%", result);
        }
    }

单元测试覆盖率

image

计算模块部分异常处理说明

  1. 文件读取异常
    • 设计目标
      目标:处理文件读取过程中可能出现的错误,例如文件不存在、文件权限不足或文件损坏。
    • 处理方式:捕获 IOException,并输出友好的错误信息,避免程序崩溃。
@Test
void testReadFileWithIOException() {
    // 模拟一个不存在的文件路径
    String nonExistentFilePath = "non_existent_file.txt";

    // 捕获异常并验证
    Exception exception = assertThrows(IOException.class, () -> {
        Main.readFile(nonExistentFilePath);
    });

    // 验证异常信息
    assertTrue(exception.getMessage().contains("文件不存在"));
}
  1. 词频向量构建异常(空输入)
    • 设计目标
      目标:处理词频向量构建过程中可能出现的异常,例如分词结果为空。
    • 处理方式:检查分词结果是否为空,避免空指针异常。
@Test
void testBuildVectorWithEmptyWords() {
    Map<String, int[]> vectorMap = new HashMap<>();
    List<String> emptyWords = new ArrayList<>();

    // 调用向量构建函数
    Main.buildVector(emptyWords, vectorMap, 0);

    // 验证词频向量为空
    assertTrue(vectorMap.isEmpty());
}
  1. 余弦相似度计算异常(除零错误)
    • 设计目标
      目标:处理余弦相似度计算过程中可能出现的除零错误,例如两个文本的词频向量都为零。
    • 处理方式:在计算相似度之前,检查模长是否为零,避免除零错误。
@Test
void testCalculateCosineSimilarityWithZeroVectors() {
    String emptyText1 = "";
    String emptyText2 = "";

    // 调用相似度计算函数
    double similarity = Main.calculateCosineSimilarity(emptyText1, emptyText2);

    // 验证相似度为 0
    assertEquals(0.0, similarity, 0.0001);
}
posted @ 2025-03-06 11:53  xb2555  阅读(72)  评论(0)    收藏  举报