求高效算法替换嵌套循环

leonyuann 2009-03-06 07:59:15
需求如下:
List<EntityA> eaList,list中大约25000个EntityA,EntityA定义如下:
public class EntityA{
private String id;
private String p1;
private String p2;
...
}
List<EntityB> ebList,list中大约22000个EntityB,EntityB定义如下:
public class EntityB{
private String id;
private String g1;
private String g2;
private String g3;
private String g4;
...
}

EntityA中的p1,p2与EntityB中的g1,g4分别匹配,如果都相等,则将该EntityA跟所有符合条件的EntityB写成一行输出到文件。
以下是嵌套循环的做法:
for(Iterator<EntityA> it = eaList.iterator(); it.hasNext();){
EntityA ea = it.next();
out.write(ea.getId() + "--->");
String p1 = ea.getP1();
String p2 = ea.getP2();
int i = 0;
for(Iterator<EntityB> it1 = ebList.iterator(); it1.hasNext();){
if(i == 2){
break;
}
EntityB eb = it1.next();
if (((eb.getG1().equals(p1)) && (cquad4.getG4().equals(p2)))
|| ((cquad4.getG2().equals(p1)) && (cquad4.getG3()
.equals(p2)))) {
out.write(ea.getId() + " ");
i++;
}
}
out.newLine();
}

out.close();

大概耗时40多秒,难以接受,高人有何好招儿教我?
...全文
318 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
  • 打赏
  • 举报
回复
[Quote=引用 10 楼 leonyuann 的回复:]
to java2000_net:
不能删除,因为有些业务逻辑在里边。
to zrzlj :
非常感谢你的答复,建立hashcode,再排序是个不错的办法,但据说commons的HashCodeBuilder貌似有问题,且即使排序再找的话,复杂度也不会是O(n+m)级别的吧?能详细说一下吗?多谢了。另外,如果更复杂一些的匹配条件,如:(p1 == g1 && p2 == g4 )or (p1 == g2 && p2 == g3),再用hashcode就不太好使了吧?
to nothing123 :
分有的是,主要是想借这机会…
[/Quote]

好几天没有上CSDN了,不好意思

1、如果commons的HashCodeBuilder有问题,可以自己实现一个哈,比较简单的,好像如果用netbeans的话,当按alt+insert实现hashcode方法的时候,会自己写出生成hashcode的方法的,或者自己写一个。

2、如果有更复杂的匹配条件的话,那么可以这样,给EntityA,EntityB一个接口属性的值,这个接口就定一个方法:产生hashcode的,然后EntityA,EntityB的hashcode方法由这个接口实现,那么如果匹配条件变化的话,给EntityA,EntityB实例分别注入一个你为了这种匹配写的产生hashcode的对象,这样就可以在不修改EntityA,EntityB代码的前提下实现多种匹配条件了。

3、如果先排序,在比较,算法应该是O(n+m),这个没有算上使用Arrays.sort()的方法,java api文档里说,Arrays.sort()方法的复杂度是O(n*log(n)),那么总的算法复杂度应该是O(n*log(n)+m*log(m)+m+n)

那么先排序后比较的算法复杂度为什么是O(m+n)呢,举个例子:
1 4 8 和
4 6 7 9 两个有序数列找相同的元素需要做多少次比较呢?

首先按选中第一行第一个元素,是1, 发现第二行第1个元素4比1大,很显然,第二行中不可能有和1相等的元素了。 1次比较
选中第一行第二个元素,是4, ok,和第二行第一个元素一样,两个都向前进一个元素 2次比较
拿第一行第三个元素8和第二行第三个元素7比,8>7, 说明第二行后面有可能有8 3次比较
那第一行第三个元素8和第二行第四个元素9比,8<9,说明第二行后面不可能有8了 4次比较
第一行结束,算法结束。

一个7个元素,只需要比4次,如果是无序的话,应该要比3*4=12次,因为每一个元素都要遍历另一个集合的所有元素。

最坏情况
8 10 12 14
7 9 11 13
这种情况需要比8次。。。是O(n+m)

睡觉前来看看的,可能有不对的地方哈,包涵包涵,呵呵
wafj1984 2009-03-09
  • 打赏
  • 举报
回复
不慎了解 自己点
leonyuann 2009-03-09
  • 打赏
  • 举报
回复
to java2000_net:
不能删除,因为有些业务逻辑在里边。
to zrzlj :
非常感谢你的答复,建立hashcode,再排序是个不错的办法,但据说commons的HashCodeBuilder貌似有问题,且即使排序再找的话,复杂度也不会是O(n+m)级别的吧?能详细说一下吗?多谢了。另外,如果更复杂一些的匹配条件,如:(p1 == g1 && p2 == g4 )or (p1 == g2 && p2 == g3),再用hashcode就不太好使了吧?
to nothing123 :
分有的是,主要是想借这机会和大家讨论一下算法问题,别着急!
老紫竹 2009-03-08
  • 打赏
  • 举报
回复
简单处理一下,在里层循环里,一旦找到相等的,则删除它。
这样下次循环就少了一次循环了。

所以这个用LinkedList效率也许更高一些

老紫竹CSDN论坛插件发布-竹签V1.0

jnh1983 2009-03-08
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 zrzlj 的回复:]
如果这两个List中的元素顺序是杂乱无章的,那没有办法,只能用双重循环,时间复杂度是O(n*m),但是,我们可以优先组织良好的数据结构,使得两个集合有序。

我自己觉得比较好的解决方案:
1、使用apache Commons项目里的lang包中的HashCodeBuilder为每一个实例要比较的两个字符串都生成hashcode,然后按照hashcode排序(这一点可以在获取对象装到容器中的时候就可以做到)。
2、然后比较hashcode,如果两个字符串都一样的,…
[/Quote]

我觉得在hashcode相等时,还要再比较原数据(g1,g4).因为
字符相同,hashcode一定相同,
但hashcode相同,字符不一定相同
jnh1983 2009-03-08
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 zrzlj 的回复:]
如果这两个List中的元素顺序是杂乱无章的,那没有办法,只能用双重循环,时间复杂度是O(n*m),但是,我们可以优先组织良好的数据结构,使得两个集合有序。

我自己觉得比较好的解决方案:
1、使用apache Commons项目里的lang包中的HashCodeBuilder为每一个实例要比较的两个字符串都生成hashcode,然后按照hashcode排序(这一点可以在获取对象装到容器中的时候就可以做到)。
2、然后比较hashcode,如果两个字符串都一样的,…
[/Quote]

我觉得在hashcode相等时,还要再比较原数据(g1,g4).因为
字符相同,hashcode一定相同,
但hashcode相同,字符不一定相同
jnh1983 2009-03-08
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 zrzlj 的回复:]
如果这两个List中的元素顺序是杂乱无章的,那没有办法,只能用双重循环,时间复杂度是O(n*m),但是,我们可以优先组织良好的数据结构,使得两个集合有序。

我自己觉得比较好的解决方案:
1、使用apache Commons项目里的lang包中的HashCodeBuilder为每一个实例要比较的两个字符串都生成hashcode,然后按照hashcode排序(这一点可以在获取对象装到容器中的时候就可以做到)。
2、然后比较hashcode,如果两个字符串都一样的,…
[/Quote]

哇噻,都给出具体方案了,还不给分。

我想比较hashcode应该比比较 String快吧。

不过,在hashcode相等的时候,还应该再比较一下String(g1,g4).
因为,
如果String相同,那么它们的hashcode一定相同;
但如果hashcode相同,String可能相同。
  • 打赏
  • 举报
回复
再补充一下:
EntityA和EntityB应该分别implements Comparable<EntityA>和Comparable<EntityB>
哎。。手直接写的。。。没有注意。。。
  • 打赏
  • 举报
回复
修正一下:
EntityB中的
return new HashCodeBuilder(17,37).append(p1).append(g4).toHashCode();
应该是
return new HashCodeBuilder(17,37).append(g1).append(g4).toHashCode();
  • 打赏
  • 举报
回复
如果这两个List中的元素顺序是杂乱无章的,那没有办法,只能用双重循环,时间复杂度是O(n*m),但是,我们可以优先组织良好的数据结构,使得两个集合有序。

我自己觉得比较好的解决方案:
1、使用apache Commons项目里的lang包中的HashCodeBuilder为每一个实例要比较的两个字符串都生成hashcode,然后按照hashcode排序(这一点可以在获取对象装到容器中的时候就可以做到)。
2、然后比较hashcode,如果两个字符串都一样的,hashcode也一样,这样的话,就可以在O(n+m)的时间内做完了。
例子:



//EntityA
import org.apache.commons.lang.builder.HashCodeBuilder;

public class EntityA {
private String p1;
private String p2;
private String p3;
/*
省略Setter/Getter
*/
@Override
public int hashCode() {
//使用Commons的类生成Hashcode
return new HashCodeBuilder(17,37).append(p1).append(p2).toHashCode();
}

public int compareTo(EntityA o) {
return this.hashCode() - o.hashCode();
}
}

//EntityB
public class EntityB {
private String g1;
private String g2;
private String g3;
private String g4;
/*
省略Setter/Getter
*/
@Override
public int hashCode() {
//使用Commons的类生成Hashcode,当然,你也可以自己写,但是注意顺序!
return new HashCodeBuilder(17,37).append(p1).append(g4).toHashCode();
}

public int compareTo(EntityA o) {
return this.hashCode() - o.hashCode();
}
}

//实验代码

EntityA a = new EntityA();
EntityB b = new EntityB();
a.setP1("p1");
a.setP2("p2");
b.setG1("p1");
b.setG4("p2");
System.out.println(a.hashCode() == b.hashCode());
b.setG4("p3");
System.out.println(a.hashCode() == b.hashCode());

输出true
false
说明p1 = g1, p2 = g4的时候,这两个对象的hashcode是一样的。


有了好的衡量手段,可以分别把2200个EntityA的对象和2500多个EntityB的对象放到2个List中
然后使用J2SE的Collections.sort(List list)方法对两个链表排序
注意,这个排序算法应该是一种改进的快速排序算法,算法复杂度应该在O(nlogn),这个没有验证过,反正应该是比较快的。等待高手解答。
这样的话排序的复杂度应该是O(nlongn+mlogm)

接着就好比较了

就像是两列数:1 2 3 4 5 6 7 8 9
2 4 5 6 9 10 23 24

找到相同的数的数的时候就不需要为了一个元素就要遍历第二个列表的所有元素了,比如取第一行第一个元素1,如果是以前的方法,需要遍历整个第二行才能第二行知道有没有1,而现在只要看第二行第一个元素是2,大于1,说明第二行中和第一行中的数字相等的了。

不知道我这样说的清不清楚。。。

具体没有去实现了,程序很好写的。

特别说明:也可以不用生成hashcode的方法,我这么实现完全是我个人的看法。欢迎讨论。
leonyuann 2009-03-06
  • 打赏
  • 举报
回复
高手来帮帮忙!!!
luopowusheng 2009-03-06
  • 打赏
  • 举报
回复
期待楼下高见~~

62,614

社区成员

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

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