第一次个人编程作业

Github地址:

Github链接

PSP表格:

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

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

(1)解题思路:
第一步:将文本通过命令行参数读入;
第二步:将文本内容转化为字符串存下(可以在这里把标点,空格去掉);
第三步:关键的来了,百度求 相似度算法;通过合适的来求解;我刚刚开始采用余弦定理,计算两个句子向量 如:
句子A:我喜欢晚上吃面条,喜欢中午吃米饭;
句子B:我不喜欢晚上吃面条,我们不合适;
我们可以提取每个字的出现次数(可以用map来存下)句子A:(1,2,2,1,1,2,1,1,1,1,1,1);句子B:(2,2,1,1,1,1,1,1,1,1,1,1)通过它们的向量余弦值来确定两个句子的相似度,但文本长的时候准确率不够(后面我才知道可以用词频来优化)。
最终我选择最小编辑距离算法,点这里;是指利用字符操作,把字符串A转换成字符串B所需要的最少操作数。其中,字符操作包括:删除一个字符,插入一个字符,修改一个字符。我们只要求出最小编辑距离,最后得相似度就是1-最小编辑距离/两句中更长的长度。
第四步:将答案输出到文本。

(2)流程图:

(3)核心代码实现:

可以在短文本时使用余弦定理

package com.company;

import java.io.*;
/*import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;*/

public class Main {


    public static void main(String[] args) throws IOException,NullTextException {//io异常抛出
        // write your code here
        //   ArrayList list = new ArrayList();
        //    args = new String[3];
        String filepath = args[0];
        File file = new File(filepath);
        File file2 = new File(args[1]);
        File file3 = new File(args[2]);
        System.out.println("文件的绝对路径:" + file.getAbsolutePath());
        System.out.println("文件的绝对路径:" + file2.getAbsolutePath());
        System.out.println("文件的绝对路径:" + file3.getAbsolutePath());

      /*  try {                                 文本是否读入
            Reader fr = new FileReader(filepath);
            char[] data = new char[1000];
            int length = 0;
            while ((length = fr.read(data)) > 0) {
                String str = new String(data, 0, length);
                System.out.println(str);
            }
            fr.close();
        } catch (Exception e) {
            e.printStackTrace();
        }*/
        /*File test = new File("src/sim_0.8/tese.txt");测试异常
        if(test.length() == 0)
        try {
            throw new NullTextException("null text");
        }catch (NullTextException e){
            e.printStackTrace();
        }*/
        String Str1 =io.read(file);
        String Str2 =io.read(file2);
    //编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符
        int ed = ED.getEd(Str1, Str2, Str1.length(), Str2.length());//获得最小编辑距离(动态规划)
        double ans = 1 - 1.0 * ed / Math.max(Str1.length(), Str2.length());//求得相似度
        // double bb = getSimilarity(Str_1,Str_2);余弦定理方法
        io.write(ans,file3);
        MainTest.testEd();
    }



   /*public static int  getEd2(String str1,String str2,int l1, int l2){
 //StackOverflowError堆栈溢出异常,递归不能用
        int op1 = getEd2(str1,str2,l1-1,l2)+1;
        int op2 = getEd2(str1,str2,l1,l2-1)+1;
        int op3 = getEd2(str1,str2,l1-1,l2-1);
        if(str1.charAt(l1-1)!=str2.charAt(l2-1)){
            op3 += 1;
        }
        return Math.min(Math.min(op1,op2),op3);
    }*/
    /*
    //利用余弦相似度算法
   public static doguble getSimilarity(String s1, String s2) {
           Map<Character, int[]> Mymap = new HashMap<>();//将两个字符串中的中文字符以及出现的总数封装到map中;
           for (int i = 1; i < s1.length()-2; i++) //将文本转化String时多出一些空格,减去
           {
               char d1 = s1.charAt(i); //  d1=第i个汉字,每一个汉字,标点不比较
               if(isHanZi(d1)) {
                   int[] num = Mymap.get(d1);
                   if (num != null && num.length == 2) {
                       num[0]++; //已有该字符,加1,原文的字符数量提取
                   } else {
                       num = new int[2];
                       num[0] = 1;//原文
                       num[1] = 0;//比较文
                       Mymap.put(d1, num);//将字符加入mymap
                   }
                   System.out.println(d1 + Arrays.toString(num));
               }
           }
           System.out.println(" ");
           for (int i = 1; i < s2.length()-2; i++) {//将文本转化String时多出一些空格,减去
               char d2 = s2.charAt(i);
               if(isHanZi(d2)) {
                   int[] num = Mymap.get(d2);
                   if (num != null && num.length == 2) {
                       num[1]++;
                   } else {
                       num = new int[2];
                       num[0] = 0;
                       num[1] = 1;
                       Mymap.put(d2, num);
                   }
                   System.out.println(d2 + Arrays.toString(num));
               }
           }
           double sq1 = 0;
           double sq2 = 0;
           double denuminator = 0;
           for (Map.Entry entry : Mymap.entrySet()) //用map的entryset遍历所有key-value;
           {
               int[] c = (int[]) entry.getValue();//章节1中出现的字为:Z1c1,Z1c2,Z1c3,Z1c4……Z1cn;它们在章节中的个数为:Z1n1,Z1n2,Z1n3……Z1nm;
               //章节2中出现的字为:Z2c1,Z2c2,Z2c3,Z2c4……Z2cn;它们在章节中的个数为:Z2n1,Z2n2,Z2n3……Z2nm;
               denuminator += c[0] * c[1];     //z1n1*z2n1+z1n2*z2n2...
               sq1 += c[0] * c[0];      //z1n1^2+z1n2^2+..
               sq2 += c[1] * c[1];      //Z2n1^2+z2n2^2+..
           }
           return denuminator / (Math.sqrt(sq1) * Math.sqrt(sq2));//余弦定理
       }}*/

    public static boolean isHanZi(char ch) {
        // 判断是否汉字
        return (ch >= 0x4E00 && ch <= 0x9FA5);

    }
}

长文本时,我是先用递归实现最小编辑距离,堆栈溢出了,后面改用动态规划的方法。

public static int getEd(String str1, String str2, int l1, int l2) {//动态规划求最小编辑距离
        int Distance = 0;
        int ed = 0;
        if (l1 != 0 && l2 != 0) {
            int[][] Distance_shuzu = new int[l1 + 1][l2 + 1];
            //编号
            int Bianhao = 0;
            for (int i = 0; i <= l1; i++) {//初始化,给每个字符编号
                Distance_shuzu[i][0] = Bianhao;
                Bianhao++;
            }
            Bianhao = 0;
            for (int i = 0; i <= l2; i++) {
                Distance_shuzu[0][i] = Bianhao;
                Bianhao++;
            }


            char[] Str1_CharArray = str1.toCharArray();
            char[] Str2_CharArray = str2.toCharArray();
            for (int i = 1; i <= l1; i++) {
                for (int j = 1; j <= l2; j++) {
                    if (Str1_CharArray[i - 1] == Str2_CharArray[j - 1]) {//相同不变
                        Distance = 0;
                    } else {
                        Distance = 1;
                    }

                    int Temp1 = Distance_shuzu[i - 1][j] + 1;//增
                    int Temp2 = Distance_shuzu[i][j - 1] + 1;//减
                    int Temp3 = Distance_shuzu[i - 1][j - 1] + Distance;//改

                    Distance_shuzu[i][j] = Math.min(Temp1, Temp2);//找最小的一步
                    Distance_shuzu[i][j] = Math.min(Temp3, Distance_shuzu[i][j]);

                }

            }

            ed = Distance_shuzu[l1][l2];
        }
        return ed;
    }

性能改进

内存消耗
int数组消耗了大量的空间

overview

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

测试代码

@org.junit.Test
    public static void testEd(){
        String [] testNames = new String[]{
                "src/sim_0.8/orig_0.8_add.txt",
                "src/sim_0.8/orig_0.8_del.txt",
                "src/sim_0.8/orig_0.8_dis_1.txt",
                "src/sim_0.8/orig_0.8_dis_3.txt",
                "src/sim_0.8/orig_0.8_dis_7.txt",
                "src/sim_0.8/orig_0.8_dis_10.txt",
                "src/sim_0.8/orig_0.8_dis_15.txt",
                "src/sim_0.8/orig_0.8_mix.txt",
                "src/sim_0.8/orig_0.8_rep.txt"
        };
        for (int i=0;i<testNames.length;i++) {
            System.out.println("测试"+i+':');
            double ans = Test.test(testNames[i]);
            Assert.assertEquals(0.8,ans,0.2);
        }
    }

测试结果

覆盖率

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

设计了一个空文本异常类

public class NullTextException extends IOException {

        public NullTextException(String message){
            super(message);
        }
        public NullTextException(String message,Throwable cause){
            super(message,cause);
        }
        public NullTextException(Throwable cause){
            super(cause);
        }
    }

测试一下

File test = new File("src/sim_0.8/tese.txt");测试异常
        if(test.length() == 0)
        try {
            throw new NullTextException("null text");
        }catch (NullTextException e){
            e.printStackTrace();
        }
posted @ 2020-09-25 01:13  imbA丶  阅读(153)  评论(0编辑  收藏  举报