使用pinyin4j实现自动完成的功能,汉字中有好多多音字,所以用的是二维数组去接pinyin4j转出来的音调。然后对该二维数组进行全排列,获取到所有拼接好的拼音字符串并返回。全排列时使用的是递归,但是最近发现了自动完成会导致内存溢出,查了原因发现,如果数据库中的数据过多,在调用全排列的递归时,会导致内存溢出的。想了很多办法,都快急死了现在不知道该如何解决。如果有此经验的大侠们,赶快帮帮小弟,不胜感激。我先把我递归的代码发出来,看看能优化不:
- Java code
/** * 递归 * @param strJaggedArray 需要递归的二维数组 * @return 最终返回的字符串数组 */ private static String[][] DoExchange(String[][] strJaggedArray) { int len = strJaggedArray.length; String[][] newArray = null; String[] temp = null; int Index = 0; int newlen = 0; //如果返回的拼音数组长度大于1(多音字),进行递归 if (len > 1) { int len1 = 0; int len2 = 0; if(null != strJaggedArray[0]) { len1 = strJaggedArray[0].length; } else { len1 = 1; } if(null != strJaggedArray[1]) { len2 = strJaggedArray[1].length; } else { len2 = 1; } //计算目标二维数组长度(即全排列之后的长度) newlen = len1 * len2; temp = new String[newlen]; //开始对多个拼音进行拼接 for (int i = 0; i < len1; i++) { for (int j = 0; j < len2; j++) { if (null != strJaggedArray[0] && null != strJaggedArray[1]) { //第一次进入该递归时默认拼接数组的前两个元素,从第二次开始,拼装第1个和第3个,第三次是第1个和第4个,以此类推 temp[Index] = strJaggedArray[0][i] + strJaggedArray[1][j]; Index++; } else if (null != strJaggedArray[0] && null == strJaggedArray[1]) { temp[Index] = strJaggedArray[0][i]; Index++; } else if (null == strJaggedArray[0] && null != strJaggedArray[1]) { temp[Index] = strJaggedArray[1][j]; Index++; } } } //需要递归的数组都会比传入的数组长度小1 newArray = new String[len - 1][]; //从2开始循环,是需要将newArray[0]留出来存放我们最终需要的拼接好的字符串使用 for (int i = 2; i < len; i++) { newArray[i - 1] = strJaggedArray[i]; } //这里其实是将传进来需要处理的数组第一个元素修改为我们需要的字符串。也就是说,每一次递归,都是修改原数组的第一个元素。[color=#FF0000](注意,问题就出在这里,因为每次都要把拼接好的字符串放到数组第一位,所以当字符串很长时,就会造成内存溢出。) newArray[0] = temp;[/color] System.out.println(newArray[0][0]); System.out.println(newArray[0].length); //继续递归 return DoExchange(newArray); } else { //如果递归到某一步传入的数组长度小于2,直接返回该数组 return strJaggedArray; } }
------解决方案--------------------------------------------------------
话说任何递归都可以换成尾递归,而尾递归可以优化成迭代的形式,你的栈溢出主要是递归的函数栈保存了太多的中间结果,优化成尾递归试试~
------解决方案--------------------------------------------------------
------解决方案--------------------------------------------------------
擦,不好意思,前面弄了点错误,终于大功告成,看看效果:
- Java code
package net.liuyx.test;import java.util.Arrays;public class Test333 { public static void main(String[] args) { String[][] a = { {"I","love","you"},{"Do","you","love","me","guys","?"} }; String[][] re = DoExchange(a); System.out.println(Arrays.deepToString(re)); long start = System.nanoTime(); String[][] re2 = DoExchange2(a); System.out.println(Arrays.deepToString(re2)); long duration = System.nanoTime()-start; System.out.println("未经过优化的==" + duration); } /** * 递归 * * @param handle * 需要递归的二维数组 * @return 最终返回的字符串数组 */ private static String[][] DoExchange(String[][] strJaggedArray) { long start = System.nanoTime(); // 如果返回的拼音数组长度大于1(多音字),进行递归 while (true) { if(strJaggedArray.length > 1) break; String[][] newArray = null; String[] temp = null; int Index = 0; int newlen = 0; int len1 = 0; int len2 = 0; if (null != strJaggedArray[0]) { len1 = strJaggedArray[0].length; } else { len1 = 1; } if (null != strJaggedArray[1]) { len2 = strJaggedArray[1].length; } else { len2 = 1; } // 计算目标二维数组长度(即全排列之后的长度) newlen = len1 * len2; temp = new String[newlen]; // 开始对多个拼音进行拼接 for (int i = 0; i < len1; i++) { for (int j = 0; j < len2; j++) { if (null != strJaggedArray[0] && null != strJaggedArray[1]) { // 第一次进入该递归时默认拼接数组的前两个元素,从第二次开始,拼装第1个和第3个,第三次是第1个和第4个,以此类推 temp[Index] = strJaggedArray[0][i] + strJaggedArray[1][j]; Index++; } else if (null != strJaggedArray[0] && null == strJaggedArray[1]) { temp[Index] = strJaggedArray[0][i]; Index++; } else if (null == strJaggedArray[0] && null != strJaggedArray[1]) { temp[Index] = strJaggedArray[1][j]; Index++; } } } // 需要递归的数组都会比传入的数组长度小1 newArray = new String[strJaggedArray.length - 1][]; // 从2开始循环,是需要将newArray[0]留出来存放我们最终需要的拼接好的字符串使用 for (int i = 2; i < strJaggedArray.length; i++) { newArray[i - 1] = strJaggedArray[i]; } // 这里其实是将传进来需要处理的数组第一个元素修改为我们需要的字符串。也就是说,每一次递归,都是修改原数组的第一个元素。[color=#FF0000](注意,问题就出在这里,因为每次都要把拼接好的字符串放到数组第一位,所以当字符串很长时,就会造成内存溢出。) newArray[0] = temp; System.out.println(newArray[0][0]); System.out.println(newArray[0].length); // 继续递归 strJaggedArray = newArray; } long duration = System.nanoTime() - start; System.out.println("经过优化的==" + duration); // 如果递归到某一步传入的数组长度小于2,直接返回该数组 return strJaggedArray; } /** * 递归 * @param strJaggedArray 需要递归的二维数组 * @return 最终返回的字符串数组 */ private static String[][] DoExchange2(String[][] strJaggedArray) { int len = strJaggedArray.length; String[][] newArray = null; String[] temp = null; int Index = 0; int newlen = 0; //如果返回的拼音数组长度大于1(多音字),进行递归 if (len > 1) { int len1 = 0; int len2 = 0; if(null != strJaggedArray[0]) { len1 = strJaggedArray[0].length; } else { len1 = 1; } if(null != strJaggedArray[1]) { len2 = strJaggedArray[1].length; } else { len2 = 1; } //计算目标二维数组长度(即全排列之后的长度) newlen = len1 * len2; temp = new String[newlen]; //开始对多个拼音进行拼接 for (int i = 0; i < len1; i++) { for (int j = 0; j < len2; j++) { if (null != strJaggedArray[0] && null != strJaggedArray[1]) { //第一次进入该递归时默认拼接数组的前两个元素,从第二次开始,拼装第1个和第3个,第三次是第1个和第4个,以此类推 temp[Index] = strJaggedArray[0][i] + strJaggedArray[1][j]; Index++; } else if (null != strJaggedArray[0] && null == strJaggedArray[1]) { temp[Index] = strJaggedArray[0][i]; Index++; } else if (null == strJaggedArray[0] && null != strJaggedArray[1]) { temp[Index] = strJaggedArray[1][j]; Index++; } } } //需要递归的数组都会比传入的数组长度小1 newArray = new String[len - 1][]; //从2开始循环,是需要将newArray[0]留出来存放我们最终需要的拼接好的字符串使用 for (int i = 2; i < len; i++) { newArray[i - 1] = strJaggedArray[i]; } //这里其实是将传进来需要处理的数组第一个元素修改为我们需要的字符串。也就是说,每一次递归,都是修改原数组的第一个元素。[color=#FF0000](注意,问题就出在这里,因为每次都要把拼接好的字符串放到数组第一位,所以当字符串很长时,就会造成内存溢出。) newArray[0] = temp; System.out.println(newArray[0][0]); System.out.println(newArray[0].length); //继续递归 return DoExchange2(newArray); } else { //如果递归到某一步传入的数组长度小于2,直接返回该数组 return strJaggedArray; } }}