个人项目-软件工程第二次作业

这个作业属于哪个课程 计科23级34班
这个作业要求在哪里 个人项目
这个作业的目标 进行个人编程,设计论文查重算法
Github仓库 https://github.com/username/PaperCheck

一、PSP表格

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

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

2.1 代码组织结构

项目采用简洁的模块化设计,主要包含以下组件:

PaperCheck/
├── src/
│   └── Main.kt              # 主程序入口和核心算法
├── test/
│   └── Test.kt              # 测试程序
└── data/                    # 测试数据集

2.2 核心类和函数设计

主要函数关系图:

main() 
├── check()
    ├── checkSimilarity()
        └── longestCommonSubsequence()

关键函数说明:

  1. main()函数:程序入口,负责参数解析和文件验证
  2. check()函数:核心控制函数,协调文件读取和相似度计算
  3. checkSimilarity()函数:相似度计算的主要逻辑
  4. longestCommonSubsequence()函数:LCS算法的具体实现

2.3 算法核心思想

本系统采用最长公共子序列(LCS)算法来计算文本相似度:

2.4 核心代码实现

fun longestCommonSubsequence(text1: String, text2: String): Int {
    val m = text1.length
    val n = text2.length
    val dp = Array(m + 1) { IntArray(n + 1) }
    
    for (i in 1..m) {
        for (j in 1..n) {
            if (text1[i - 1] == text2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])
            }
        }
    }
    
    return dp[m][n]
}

三、性能分析

消耗最大的函数longestCommonSubsequence()

  • 时间复杂度:O(m×n)
  • 空间复杂度:O(m×n)
  • 占总执行时间的约80.18%

PixPin_2025-09-21_16-58-54

性能瓶颈原因

  1. 内存占用过大:二维DP数组占用O(m×n)空间
  2. 字符串处理效率低:多次字符串操作和正则表达式匹配
  3. 文件I/O:每次都重新读取整个文件

四、异常说明

1. FileNotFoundException异常

  • 设计目标:处理文件不存在的情况
  • 处理策略:输出错误信息并优雅退出
  • 测试样例
fun testFileNotFound() {
    val orgFile = File("nonexistent.txt")
    val changedFile = File("data/orig_0.8_add.txt")
    val outputFile = File("output.txt")
    check(orgFile, changedFile, outputFile)
}
  • 错误场景:用户提供了不存在的文件路径

2. SecurityException异常

  • 设计目标:处理文件权限不足的情况
  • 处理策略:提示权限错误并建议解决方案
  • 测试样例
fun testFilePermissionDenied() {
    // 创建只读文件测试权限异常
    val readOnlyFile = File("readonly.txt")
    readOnlyFile.createNewFile()
    readOnlyFile.setReadOnly()
    // 测试写入操作
}
  • 错误场景:输出文件所在目录没有写权限

3. 参数异常

  • 设计目标:处理无效的命令行参数
  • 处理策略:显示使用帮助信息
  • 测试样例
fun testInvalidArguments() {
    main(arrayOf()) // 空参数数组
}
  • 错误场景:用户未提供足够的命令行参数

四、PSP表格总结

通过本次项目开发,实际耗时比预估时间多出75分钟,主要超时原因:

  1. 需求分析阶段:对LCS算法的理解和选择花费了更多时间
  2. 编码阶段:异常处理和边界情况的处理比预期复杂
  3. 外部因素:外部事务影响导致分心工作

五、项目总结与改进计划

5.1 项目成果

  • 成功实现了基于LCS算法的论文查重系统
  • 达到了较高的代码质量和测试覆盖率
  • 具备良好的异常处理机制

5.2 存在的不足

  1. 对于超大文件的处理效率有待提升
  2. 算法对同义词替换的检测能力有限
  3. 缺少对文档结构的考虑

六、学习心得

通过本次作业,我深入理解了:

  1. 算法设计:LCS算法的原理和应用
  2. 软件工程:PSP流程的重要性和实用性
  3. 测试驱动:单元测试对代码质量的保障作用
  4. 异常处理:健壮性设计的重要性

这次项目让我认识到,一个看似简单的功能背后需要考虑众多细节,从算法选择到异常处理,从性能优化到用户体验,每个环节都需要仔细设计和实现。

posted @ 2025-09-21 17:03  Nyanya--  阅读(34)  评论(0)    收藏  举报