java二维数组的问题,高手请进!解决了高分相送!

莫扎特_Mozart 2012-08-19 02:18:50
使用pinyin4j实现自动完成的功能,汉字中有好多多音字,所以用的是二维数组去接pinyin4j转出来的音调。然后对该二维数组进行全排列,获取到所有拼接好的拼音字符串并返回。全排列时使用的是递归,但是最近发现了自动完成会导致内存溢出,查了原因发现,如果数据库中的数据过多,在调用全排列的递归时,会导致内存溢出的。想了很多办法,都快急死了现在不知道该如何解决。如果有此经验的大侠们,赶快帮帮小弟,不胜感激。我先把我递归的代码发出来,看看能优化不:


/**
* 递归
* @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];
}
//这里其实是将传进来需要处理的数组第一个元素修改为我们需要的字符串。也就是说,每一次递归,都是修改原数组的第一个元素。(注意,问题就出在这里,因为每次都要把拼接好的字符串放到数组第一位,所以当字符串很长时,就会造成内存溢出。)
newArray[0] = temp;

System.out.println(newArray[0][0]);
System.out.println(newArray[0].length);
//继续递归
return DoExchange(newArray);
}
else
{
//如果递归到某一步传入的数组长度小于2,直接返回该数组
return strJaggedArray;
}
}
...全文
362 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
莫扎特_Mozart 2012-08-28
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 的回复:]

引用 6 楼 的回复:

话说任何递归都可以换成尾递归,而尾递归可以优化成迭代的形式,你的栈溢出主要是递归的函数栈保存了太多的中间结果,优化成尾递归试试~

同意,全排列完全可以用非传统递归方式或者非递归方式实现,楼主搜一下。
[/Quote]
嗯,谢谢关注,已经用另外的方式解决了
莫扎特_Mozart 2012-08-28
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 的回复:]

引用 4 楼 的回复:

引用 3 楼 的回复:

你这个以全排列就无敌了肯定溢出 为什么要全排列

呵呵,全排列之后要拼成字符串给自动完成使用呢。


挺好玩的程序。 您能不能把调用处的代码也贴上来??
我好想看看。
[/Quote]

额。。这还需要我给你啊,自己写一个main方法去调用么
莫扎特_Mozart 2012-08-28
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 的回复:]

擦,不好意思,前面弄了点错误,终于大功告成,看看效果:
Java code

package net.liuyx.test;

import java.util.Arrays;

public class Test333 {
public static void main(String[] args) {
String[][] a = {
……
[/Quote]
这位兄弟,辛苦了,最近几天一直忙的没时间看这个,才看到这些信息。
首先,这个递归的方式现在已经可以不用考虑了,因为数据量稍微大点就会出问题,我要把递归完成之后的字符串返回去和目标字符串做对比。
现在的思路就是在它递归的时候递归一个我比一个,就不再进行拼接了,所以刚开始的内存溢出问题也就解决了。看在你这么辛苦的份上,给你分了~呵呵
痕枫冷 2012-08-23
  • 打赏
  • 举报
回复
擦,不好意思,前面弄了点错误,终于大功告成,看看效果:

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;
}
}



}


最后程序输出:
经过优化的==1956
[[I, love, you], [Do, you, love, me, guys, ?]]
IDo
18
[[IDo, Iyou, Ilove, Ime, Iguys, I?, loveDo, loveyou, lovelove, loveme, loveguys, love?, youDo, youyou, youlove, youme, youguys, you?]]
未经过优化的==310095


这回没错了,lz给分哈。。。哈哈
痕枫冷 2012-08-23
  • 打赏
  • 举报
回复
下面是我用System.nanoTime()测试出的结果:
IDo
18
==========经过优化的
443073
[[IDo, Iyou, Ilove, Ime, Iguys, I?, loveDo, loveyou, lovelove, loveme, loveguys, love?, youDo, youyou, youlove, youme, youguys, you?]]
IDo
18
[[IDo, Iyou, Ilove, Ime, Iguys, I?, loveDo, loveyou, lovelove, loveme, loveguys, love?, youDo, youyou, youlove, youme, youguys, you?]]
未经过优化的==12061825829819


效果太明显了,lz请看
痕枫冷 2012-08-22
  • 打赏
  • 举报
回复

/**
* 递归
*
* @param strJaggedArray
* 需要递归的二维数组
* @return 最终返回的字符串数组
*/
private static String[][] DoExchange(String[][] strJaggedArray) {
// 如果返回的拼音数组长度大于1(多音字),进行递归
while (strJaggedArray.length > 1) {
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;
}
// 如果递归到某一步传入的数组长度小于2,直接返回该数组
return strJaggedArray;
}

这样试试?
dracularking 2012-08-21
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

话说任何递归都可以换成尾递归,而尾递归可以优化成迭代的形式,你的栈溢出主要是递归的函数栈保存了太多的中间结果,优化成尾递归试试~
[/Quote]
同意,全排列完全可以用非传统递归方式或者非递归方式实现,楼主搜一下。
learningBird 2012-08-21
  • 打赏
  • 举报
回复
原来有pinyin4J这东东的。学习学习。
scbb 2012-08-21
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 的回复:]

引用 3 楼 的回复:

你这个以全排列就无敌了肯定溢出 为什么要全排列

呵呵,全排列之后要拼成字符串给自动完成使用呢。
[/Quote]

挺好玩的程序。 您能不能把调用处的代码也贴上来??
我好想看看。
痕枫冷 2012-08-20
  • 打赏
  • 举报
回复
话说任何递归都可以换成尾递归,而尾递归可以优化成迭代的形式,你的栈溢出主要是递归的函数栈保存了太多的中间结果,优化成尾递归试试~
痕枫冷 2012-08-20
  • 打赏
  • 举报
回复
话说任何递归都可以换成尾递归,而尾递归可以优化成迭代的形式,你的栈溢出主要是递归的函数栈保存了太多的中间结果,优化成尾递归试试~
莫扎特_Mozart 2012-08-19
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

你这个以全排列就无敌了肯定溢出 为什么要全排列
[/Quote]
呵呵,全排列之后要拼成字符串给自动完成使用呢。
zqfddqr 2012-08-19
  • 打赏
  • 举报
回复
你这个以全排列就无敌了肯定溢出 为什么要全排列
莫扎特_Mozart 2012-08-19
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 的回复:]

如果数据量大,就把JVM内存调大点吧。
如果数据量太大了,就不要把所有数据都一次性放到数组里。往往也不需要这样做。
[/Quote]
嗯,思路我有,但是能不能再提示一些?谢谢了!
brightyq 2012-08-19
  • 打赏
  • 举报
回复
如果数据量大,就把JVM内存调大点吧。
如果数据量太大了,就不要把所有数据都一次性放到数组里。往往也不需要这样做。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧