二维数组中最大连通子数组之和
一、目的
- 熟悉编程风格
- 实现简单单元测试
- 简单的性能分析
- 在上次的最大子数组上实现进阶,求最大连通子数组
二、编程
1、程序分析
所用函数:
主函数(Main)
最大子数组函数(array)
判断是否存在其他字符函数(用于输出错误(isnum))、是否不为纯数字
文件读取函数(SparseArrayFromFile)
读取文件时是否存在其他字符(isnumber)
2、代码解读以及运行结果
2.1、代码解读
文件读取------SparseArrayFromFile()
1 //为保存的数组分配空间 2 public static int[][] datas; 3 public static int[][] SparseArrayFromFile(String path){ 4 //将稀疏矩阵从文件中读取出来 5 BufferedReader br = null; 6 BufferedReader br1 = null; 7 try { 8 InputStreamReader isr = new InputStreamReader(new FileInputStream(new File(path))); 9 InputStreamReader isr1 = new InputStreamReader(new FileInputStream(new File(path))); 10 br = new BufferedReader(isr); 11 br1 = new BufferedReader(isr1); 12 String res = null; 13 int i = 1; 14 int n,s; 15 n = Integer.valueOf(br.readLine());//行 16 s = Integer.valueOf(br.readLine());//列 17 if(!isnumber(br1)){//判断是否存在非整数(*等符号) 18 datas = new int[n+2][s+2]; 19 for (int x = 0;x < n+2;x++){ 20 for (int y = 0;y < s+2;y++){ 21 datas[x][y] = Integer.MAX_VALUE; 22 } 23 } 24 }else{ 25 //为保存的数组分配空间 26 datas = new int[n+2][s+2]; 27 for(int x = 0;x < n+2;x++){ 28 for (int y = 0;y < s+2;y++){ 29 datas[x][y] = Integer.MIN_VALUE; 30 } 31 } 32 //按行读取 33 while(null != (res = br.readLine())) { 34 if (null != res) { 35 //按行读取的字符串按逗号分割,得到一个String数组 36 String[] str = res.split(","); 37 //依此转为int型存入分配好的空间数组中 38 for (int k = 0; k < str.length; k++) { 39 //判断是否是负数,将其后的数直接强转为整型 40 if (str[k].charAt(0) == '-') { 41 String num = ""; 42 for (int m = 1; m < str[k].length(); m++) { 43 num += str[k].charAt(m); 44 } 45 int snum = Integer.valueOf(num); 46 datas[i][k+1] = -snum; 47 } else {//为正数时,直接强转为整型 48 datas[i][k+1] = Integer.valueOf(str[k]); 49 } 50 } 51 i++;//行数加1 52 } 53 } 54 } 55 br.close(); 56 isr.close(); 57 } catch (Exception e) { 58 e.printStackTrace(); 59 } 60 return datas; 61 }
判断其他字符------isnumber()
1 //判断是否存储不为数字的其他字符 2 public static boolean isnumber(BufferedReader br){ 3 boolean flag = true; 4 String res = ""; 5 try{ 6 int n = Integer.valueOf(br.readLine()); 7 int s = Integer.valueOf(br.readLine()); 8 while(null != (res = br.readLine())){ 9 if(res != null){ 10 //按行读取的字符串按逗号分割,得到一个String数组 11 String[] str = res.split(","); 12 for(int i = 0;i < str.length;i++){ 13 //判断是否存在字符,多个字符连接也可判断 14 if(str[i].charAt(0) == '-'){ 15 for(int k = 1;k < str[i].length();k++){ 16 if(str[i].charAt(k)-'0' < 10 && str[i].charAt(k)-'0' >= 0) 17 continue; 18 else{ 19 flag = false; 20 break; 21 } 22 } 23 }else{ 24 for(int k = 0;k < str[i].length();k++){ 25 if(str[i].charAt(k)-'0' < 10 && str[i].charAt(k)-'0' >= 0) 26 continue; 27 else{ 28 flag = false; 29 break; 30 } 31 } 32 } 33 if (!flag) 34 break; 35 } 36 if (!flag) 37 break; 38 } 39 } 40 br.close(); 41 }catch (Exception e){ 42 e.printStackTrace(); 43 } 44 return flag; 45 }
主函数------Main()
1 public static void main(String[] args) { 2 FileRead fd = new FileRead(); 3 int[][] datas = fd.SparseArrayFromFile("D:\\IDEA\\Workspaces\\MaxArray\\data\\3.txt"); 4 int res = Integer.MIN_VALUE; 5 if (!isnum(datas)){ 6 System.out.println("字符存储错误"); 7 }else { 8 int[][] ary = new int[datas.length][datas[0].length]; 9 for (int i = 1; i < datas.length - 1; i++) {//行 10 for (int j = 1; j < datas[0].length - 1; j++) {//列 11 ary = memset(datas, ary); 12 res = Math.max(res, array(i, j, ary, Integer.MIN_VALUE)); 13 } 14 } 15 System.out.println(res); 16 } 17 }
求最大子数组------array()
算法思路:
找到第一个点,找其上、下、左、右四个方向中找最大值,然后将其变成最小值,然后存储器最大值,在移动时,发现其范围内的其他正数直接加入。
1 //求最大子数组 2 /** 3 * 算法思路: 4 * 找到每一个点的相邻点中的最大值(上、下、左、右),相加,存储最大值,加一位数,将其更替为最小值,防止回走 5 * */ 6 public static int array(int x,int y,int[][] datas,int temp){ 7 int len = (datas.length-1)*(datas[0].length-1); 8 int res = Integer.MIN_VALUE; 9 temp = datas[x][y]; 10 int m = x,n = y; 11 for(int i = 0;i < len;i++){ 12 res = Math.max(res,temp); 13 datas[m][n] = Integer.MIN_VALUE; 14 if(datas[m-1][n] > datas[m+1][n] && datas[m-1][n] > datas[m][n+1] && datas[m-1][n] > datas[m][n-1]){//上 15 if(datas[m+1][n] > 0 && datas[m+1][n] != Integer.MIN_VALUE){ 16 temp += datas[m+1][n]; 17 datas[m+1][n] = Integer.MIN_VALUE; 18 }else if(datas[m][n-1] > 0 && datas[m][n-1] != Integer.MIN_VALUE){ 19 temp += datas[m][n-1]; 20 datas[m][n-1] = Integer.MIN_VALUE; 21 }else if(datas[m][n+1] > 0 && datas[m][n+1] != Integer.MIN_VALUE){ 22 temp += datas[m][n+1]; 23 datas[m][n+1] = Integer.MIN_VALUE; 24 } 25 temp += datas[m-1][n]; 26 m = m - 1; 27 n = n; 28 }else if(datas[m+1][n] > datas[m-1][n] && datas[m+1][n] > datas[m][n-1] && datas[m+1][n] > datas[m][n+1]){//下 29 if(datas[m-1][n] > 0 && datas[m-1][n] != Integer.MIN_VALUE){ 30 temp += datas[m-1][n]; 31 datas[m-1][n] = Integer.MIN_VALUE; 32 }else if(datas[m][n+1] > 0 && datas[m][n+1] != Integer.MIN_VALUE){ 33 temp += datas[m][n+1]; 34 datas[m][n+1] = Integer.MIN_VALUE; 35 }else if(datas[m][n-1] > 0 && datas[m][n-1] != Integer.MIN_VALUE){ 36 temp += datas[m][n-1]; 37 datas[m][n-1] = Integer.MIN_VALUE; 38 } 39 temp += datas[m+1][n]; 40 m = m + 1; 41 n = n; 42 }else if(datas[m][n-1] > datas[m+1][n] && datas[m][n-1] > datas[m-1][n] && datas[m][n-1] > datas[m][n+1]){//左 43 if(datas[m-1][n] > 0 && datas[m-1][n] != Integer.MIN_VALUE){ 44 temp += datas[m-1][n]; 45 datas[m-1][n] = Integer.MIN_VALUE; 46 }else if(datas[m+1][n] > 0 && datas[m+1][n] != Integer.MIN_VALUE){ 47 temp += datas[m+1][n]; 48 datas[m+1][n] = Integer.MIN_VALUE; 49 }else if(datas[m][n+1] > 0 && datas[m][n+1] != Integer.MIN_VALUE){ 50 temp += datas[m][n+1]; 51 datas[m][n+1] = Integer.MIN_VALUE; 52 } 53 temp += datas[m][n-1]; 54 m = m; 55 n = n - 1; 56 }else if(datas[m][n+1] > datas[m+1][n] && datas[m][n+1] > datas[m-1][n] && datas[m][n+1] > datas[m][n-1]){//右 57 if(datas[m-1][n] > 0 && datas[m-1][n] != Integer.MIN_VALUE){ 58 temp += datas[m-1][n]; 59 datas[m-1][n] = Integer.MIN_VALUE; 60 }else if(datas[m][n-1] > 0 && datas[m][n-1] != Integer.MIN_VALUE){ 61 temp += datas[m][n-1]; 62 datas[m][n-1] = Integer.MIN_VALUE; 63 }else if(datas[m+1][n] > 0 && datas[m][n+1] != Integer.MIN_VALUE){ 64 temp += datas[m+1][n]; 65 datas[m+1][n] = Integer.MIN_VALUE; 66 } 67 temp += datas[m][n+1]; 68 m = m; 69 n = n + 1; 70 } 71 datas[m][n] = Integer.MIN_VALUE; 72 } 73 return res; 74 }
判断输出错误值------isnum()
1 //判断数组是否存在其他字符 2 public static boolean isnum(int[][] datas){ 3 boolean flag = true; 4 if(datas[0][0] == Integer.MAX_VALUE) 5 flag = false; 6 return flag; 7 }
2.2、结果展示
文件1

结果:

文件2

结果:

文件3

结果:

文件4

结果:

3、单元测试
这里使用了三个测试,结果如下
测试代码:
1 public class MaxArrayTest extends MaxArray { 2 private MaxArray ma; 3 private FileRead fr; 4 @Test 5 public void array1() { 6 int[][] datas = fr.SparseArrayFromFile("D:\\IDEA\\Workspaces\\MaxArray\\data\\1.txt"); 7 int res = Integer.MIN_VALUE; 8 int[][] ary = new int[datas.length][datas[0].length]; 9 for(int i = 1;i < datas.length-1;i++){//行 10 for(int j = 1;j < datas[0].length-1;j++){//列 11 ary = memset(datas,ary); 12 res = Math.max(res,array(i,j,ary,Integer.MIN_VALUE)); 13 } 14 } 15 assertEquals(res,-1); 16 } 17 @Test 18 public void array2() { 19 int[][] datas = fr.SparseArrayFromFile("D:\\IDEA\\Workspaces\\MaxArray\\data\\2.txt"); 20 int res = Integer.MIN_VALUE; 21 int[][] ary = new int[datas.length][datas[0].length]; 22 for(int i = 1;i < datas.length-1;i++){//行 23 for(int j = 1;j < datas[0].length-1;j++){//列 24 ary = memset(datas,ary); 25 res = Math.max(res,array(i,j,ary,Integer.MIN_VALUE)); 26 } 27 } 28 assertEquals(res,23); 29 } 30 @Test 31 public void array3() { 32 int[][] datas = fr.SparseArrayFromFile("D:\\IDEA\\Workspaces\\MaxArray\\data\\3.txt"); 33 assertEquals(isnum(datas),false); 34 } 35 @Test 36 public void array4() { 37 int[][] datas = fr.SparseArrayFromFile("D:\\IDEA\\Workspaces\\MaxArray\\data\\4.txt"); 38 int res = Integer.MIN_VALUE; 39 int[][] ary = new int[datas.length][datas[0].length]; 40 for(int i = 1;i < datas.length-1;i++){//行 41 for(int j = 1;j < datas[0].length-1;j++){//列 42 ary = memset(datas,ary); 43 res = Math.max(res,array(i,j,ary,Integer.MIN_VALUE)); 44 } 45 } 46 assertEquals(res,25); 47 } 48 }
结果展示:

三、性能分析结果及改进
1、性能分析
使用工具:JProfilter
JProfilter简介:
JProfiler是一个全功能的Java剖析工具(profiler),主要用于检查和跟踪系统(限于Java 开发的)的性能。JProfiler可以通过时时的监控系统的内存使用情况,随时监视垃圾回收,线程运行状况等手段,从而很好的监视JVM运行情况及其性能。它把CPU、线程和内存的剖析组合在一个强大的应用中。JProfiler可提供许多IDE整合和应用服务器整合功能。
代码基础性能,如下图所示:

内存的使用占比较小,空闲的空间比较大,代码中的数组空间利用率不高。
Live momery (内存视图)
所有记录对象的内存试图:


CPU views(cpu视图)
调用图:

2、改进方法
- 使用动态数组存储数据,提高空间的利用效率
- 修改判断方法,提高代码执行效率。
四、代码覆盖率

测试显示(由于IDEA覆盖率的显示只是显示在边缘,所以这里直接贴图,方便观看):
MaxArray函数代码覆盖率:




FileRead函数覆盖率:




以上为所有代码的覆盖率显示,行号旁的绿色表示覆盖的代码,红色表示未覆盖的代码。

浙公网安备 33010602011771号