我了解ArrayList<>
搜索速度最快(O(1)
与O(n)
),LinkedList<>
的插入速度最快;正在删除(O(1)
与O(n)
)。
我的问题是,如果使用这两者的组合,检查多个列表(&gt; 2)的常用元素的最佳方法是什么?
当前方法 使用三个列表和一个迭代方法:
out:
for(int a = 0; a < list1.size(); a++) {
for(int b = 0; b < list2.size(); b++) {
for(int c = 0; c < list3.size(); c++) {
if(list1.get(a) == list2.get(b) && list1.get(a) == list3.get(c) ) {
System.out.println(list1.get(a)); // list2.get(b) or list3.get(c) could have been subbed
break out;
}
}
}
}
如何针对效率进行优化?
修改
感谢许多有用的回复:)
我发现最好的方法是使用List .retainAll()
函数。
再次,为了找到三个列表中的共同元素,我已经改进了下面的方法。
list1.retainAll(list2);
list1.retainAll(list3);
for(int i : list1) {
System.out.println(i);
}
答案 0 :(得分:2)
假设元素实现hashCode
,您可以获得所有列表中元素数量的预期时间线性:
public static <T> Set<T> commonElements(List<? extends T> list1, List<? extends T>... lists) {
// use LinkedList for efficient delete operation
// make sure elements are distinct to not check the same element multiple times
List<T> commonElements = new LinkedList<>(new HashSet<>(list1));
for (List<? extends T> l : lists) {
// use HashSet for fast contains check
// keep only elements in the list
commonElements.retainAll(new HashSet<>(l));
}
return new HashSet<>(commonElements);
}
这比您的方法更快,因为HashSet
允许在O(1)
预期时间内进行查找。
请注意,对于小输入列表,使用此方法可以使性能更差。
答案 1 :(得分:1)
如果您正在寻找性能,最好编写一个使用哈希查找的API。 list.retainAll()虽然是一个干净的api调用,但在内部它会进行大量的处理,特别是如果传递的参数也是一个列表。在这里看看数组列表的retainAll()的实现 -
您可以查看正在使用的列表的实现,并查看是否可以满足您的性能要求。如果没有,你可以尝试这样的事情......写一个api来返回共同的元素。
private static Set getCommonElements (List dataList, Set dataSet) {
Set commonDataSet = new LinkedHashSet();
if (dataSet == null || dataSet.isEmpty())
return commonDataSet;
for (Object elem: dataList) {
if (dataSet.contains(elem)) {//Hash based look up. Will be faster.
commonDataSet.add(elem);
}
}
return commonDataSet;
}
然后重复调用,如下所示
Set resultSet= new LinkedHashSet(list1);
resultSet= getCommonElements(list2, resultSet);
resultSet= getCommonElements(list3, resultSet);
如果您不关心订单,可以使用hashset而不是linkedhashset。
这样做的一个问题是,这是迭代列表中的元素,这些元素将高于公共元素。如果我们可以遍历公共元素并在列表中查找,那会好得多。但为此,您可能必须将列表中的数据保存在散列烘焙列表/集中或维护排序列表。否则查找将是昂贵的。
答案 2 :(得分:0)
您可以使用Java中的HashMap对其进行优化。 假设您有n个列表,每个列表包含m个元素
算法:
make hashmap h;
loop i=0 to m
loop j=0 to n
increment j[i] key in hashmap h
loop end
loop end
loop i=0 to m for any list
check hashmap value for the element, if equals to n
print element
复杂度o(nm),如果n <&lt;&lt;那么,复杂性(n)
答案 3 :(得分:0)
使用retainAll(List<>)
函数而不是迭代每个元素可以显着减少运行时间并提高可读性。
新强>
list1.retainAll(list2);
list1.retainAll(list3);
<强>旧强>
out:
for(int a = 0; a < list1.size(); a++) {
for(int b = 0; b < list2.size(); b++) {
for(int c = 0; c < list3.size(); c++) {
if(list1.get(a) == list2.get(b) && list1.get(a) == list3.get(c) ) {
System.out.println(list1.get(a));
break out;
}
}
}
}