问题:返回一个二维整数数组中最大联通子数组的和

思路:把数按行分成几个一维数组,对于该一维数组,求出他们的最大连续数组之和,并且记录下最大连续数组的第一位和最后一位的位置,之后判断几个一维数组的最大连续数组的位置是否相接或包括(如,第一行是1和4,第二行是3和5,这样就相连)。最后在加上没有包括的正数(必须在上一行的最大连续数组的第一位和最后一位的位置之间)。输出之前之和就行。

一、实现代码

package test;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;

public class MaxIntArray {
public static void main(String[] args) throws IOException {

Integer[][] c=new Integer[100][];

c=ReadFile("C:\\Users\\Administrator\\Desktop\\arr.txt");
for(int i=0;i<c.length;i++){
for(int j=0;j<c[0].length;j++){
System.out.print(c[i][j]+" ");
}
System.out.println();
}
// System.out.print(c[2][2]);
System.out.println("1:"+GetMaxSUM(c));
// System.out.println("2"+MaxSUM(c));
}
public static Integer[][] ReadFile(String str){
FileReader file = null;

try {
file = new FileReader(str);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
System.out.println("文件测试数据如下:");
BufferedReader br = new BufferedReader(file);//读取文件
try {
String line = br.readLine();//读取一行数据
int lenx = Integer.parseInt(line);//将数据转化为int类型
line = br.readLine();//读取一行数据
int leny = Integer.parseInt(line);//将数据转化为int类型
// System.out.println(lines);

String []sp = null;
String [][]c = new String[lenx][leny];
Integer[][] cc = new Integer[lenx][leny];
int count=0;
while((line=br.readLine())!=null) {//按行读取
sp = line.split(" ");//按空格进行分割
// System.out.println("Length:"+sp.length);
// System.out.println("sp:"+sp[0]);
for(int i=0;i<sp.length;i++){
c[count][i] = sp[i];
}
count++;
}
for(int i=0;i<lenx;i++){
for(int j=0;j<leny;j++){
cc[i][j] = Integer.parseInt(c[i][j]);
// System.out.print(cc[i][j]+" ");
}
// System.out.println();
}
return cc;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}

public static int GetMaxSUM(Integer[][] a){
int n=a.length;
int m=a[0].length;
//分块
Integer[] Max=new Integer[100];
Integer[] Begin=new Integer[100];
Integer[] End=new Integer[100];
Integer[] b=new Integer[100];
for(int i=0;i<n;i++)
{
//按行分组
for(int j=0;j<m;j++)
{
b[j]=a[i][j];

}
MaxIntArray(b,Max,Begin,End,m,i);
}

int max=Max[0];
for(int i=0;i<n-1;i++)
{
if((Begin[i]<=End[i+1]&&Begin[i]>=Begin[i+1])||(End[i]<=End[i+1]&&End[i]>=Begin[i+1]))
{
max=Max[i+1]+max;
}
else
{
//如果不能直接连通,判断代价是否合适
if(Begin[i]>End[i+1])
{
int t = Begin[i]-End[i+1];
int s = Begin[i];
int temp=0;
for(int k=0;k<t;k++)
{
temp+=a[i+1][s-k];
}
if(temp+Max[i+1]>0)
max=temp+Max[i+1];
}
if(End[i]<Begin[i+1])
{
int t = Begin[i+1]-End[i];
int s = End[i];
int temp=0;
for(int k=0;k<t;k++)
{
temp+=a[i+1][s+k];
}
if(temp+Max[i+1]>0)
max=temp+Max[i+1];
}
}
}
return max;
}
public static void MaxIntArray(Integer[] a,Integer[] max,Integer[] begin,Integer[] end,int n,int index){

Integer[] Max=new Integer[100];
Max[0] = 0;
int i = 0;//数组下标
int j = 0;//最大值数组下标
int temp=0;//中间变量
//记录子数组的起始位置和末位
// Integer[] Bg=new Integer[100];
Integer[] Bg={-1,-1,-1,-1,-1};
Integer[] Ed=new Integer[100];
while(i<n){
if(temp+a[i]>=Max[j])
{
temp=temp+a[i];
Max[j]=temp;
if(Bg[j]==-1)
Bg[j]=i;
Ed[j]=i;
i++;
}
else if(temp+a[i]<Max[j]&&temp+a[i]>0)
{
temp=temp+a[i];
i++;
}
else if(temp+a[i]<=0)
{
i++;
j++;
Max[j]=0;
temp=0;
}

}
max[index] = Max[0];
int q=0;
for(int k=0;k<=j;k++){
if(Max[k]>max[index])
{
max[index]=Max[k];
q=k;
}
}
begin[index]=Bg[q];
end[index]=Ed[q];
}
}

二、单元测试

2.1 测试环境搭建

完成项目的创建后,点击 文件File-点击新建,选择Junit Test Case,创建 测试类

 

 2.2 创建测试用例

因为二维数组是从TXT文件中进行输入的,所以首先应该创建用于数据读取的TXT文件,我一共创建了三组测试用例;

arr.txt

3
3
1 2 3
3 4 5
2 4 5

arr2.txt

4
4
1 6 -9 3
-4 9 3 6
3 -6 1 6
3 9 4 -5

arr2.txt  

2
2
1 1
1 1

 

 

注意:在TXT文件中写入二维数组的时候要先写行,回车在写列,最后写二维数组。

正确操作后会出现如下窗口:

 

 2.3创建测试代码

接着在Text类里面编写测试的代码

测试代码:

package test;

import org.junit.Test;

import static org.junit.Assert.*;
import static test.MaxIntArray.GetMaxSUM;
import static test.MaxIntArray.MaxSUM;
import static test.MaxIntArray.ReadFile;

public class MaxIntArrayTest {

    @Test
    public void test1() {
        String str="C:\\Users\\36072\\Desktop\\arr1.txt";
        Integer[][] c=ReadFile(str);
        System.out.println("MaxSUM:"+GetMaxSUM(c));
    }
    @Test
    public void test2() {
        String str="C:\\Users\\36072\\Desktop\\arr2.txt";
        Integer[][] c=ReadFile(str);
        System.out.println("MaxSUM:"+GetMaxSUM(c));
    }
    @Test
    public void test3() {
        String str="C:\\Users\\36072\\Desktop\\arr3.txt";
        Integer[][] c=ReadFile(str);
        System.out.println("MaxSUM:"+GetMaxSUM(c));
    }
    @Test
    public void test4() {
        String str="C:\\Users\\36072\\Desktop\\arr4.txt";
        Integer[][] c=ReadFile(str);
        System.out.println("MaxSUM:"+GetMaxSUM(c));
    }

}

测试结果:

 

 三组数据都通过了测试。

三、代码覆盖率

3.1Jacoco插件安装

Eclipse下依次点击 Help->Eclipse Marketplace->搜索EclEmma
在这里插入图片描述
接下来按步骤安装即可。
安装成功后,在Window->Show View->Other中找到Coveage可以打开界面

 3.2 覆盖率检测

选择想要测试的单元测试文件或者文件夹,编写成功后右键项目选择Coverage As -> JUnit Test,
执行后效果如图:

对单元测试代码进行代码覆盖率检测:

对程序代码进行代码覆盖率检测(一部分截图):

 

 绿色:代码被执行过 黄色:代码部分被执行过 红色:代码没有被执行过

  成功后会出现统计信息。

 

可以看到每个方法中执行到的代码和未执行的代码,可以看到代码测试覆盖率。看代码,是取得随机数,if判断可能出现不满足,可能满足的情况, 需要多次执行该代码,得到多次的代码覆盖率,然后吧多次得到的覆盖率合并,得到这个类总的代码测试覆盖率。

小结

1、通过Eclipse插件可以快速验证测试用例的代码覆盖率,在大型项目中,合格的测试用例覆盖率能够很好的减少因临时修改代码而导致的重大BUG,但不建议盲目追求代码覆盖率,尤其是中小型项目。

如果要测试整个项目中代码的测试覆盖率,可能比较麻烦,至少需要吧所有代码的测试类执行一遍,并且把所有代码执行的路径都考虑到才准确。
2、别忘记测试异常情况,空指针,或者其他异常后,执行异常代码,也会增加代码测试覆盖率的。
3、如果得到代码测试覆盖率比较高,显而易见能看出代码安全性会比较能保证。