Java中大集合<Long>求交集的方法比较

背景

项目中使用到List求交集,很容易想到collecion.retainAll()方法,但是在数据量比较大时,这个方法效率并不高。本文研究了几种常用的方法,以供大家参考。

方法

【首先】 梳理下思路,List去重一般有几种方法。

  1. 『外层遍历+内层遍历』查找:

复杂度O(NM) ,一般使用contains()检查是否包含

  1. 『外层遍历+内层Hash』查找:

复杂度O(N),一般将内层List转化为HashSet实现

  1. 『外层遍历+内层bitMap』查找:

复杂度O(N),一般将内层List转化为字节映射实现

【其次】 这里其实忽略了一个点,就是 『单层遍历』中,检查 元素不包含 时,需要将这个 元素移除 (即remove方法)。remove时,也会导致性能问题。

这里面我们使用Java8中 java.util.AbstractCollection#retainAll 方法来验证下我们的思路。

// Java8 中 方法:java.util.AbstractCollection#retainAll
public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    boolean modified = false;
    Iterator<E> it = iterator();
    
    // 1. 外层遍历
    while (it.hasNext()) {
        
        // 2. 内层查找『是否包含』
        if (!c.contains(it.next())) {
        
            // 3. 不包含时,移除外层元素
            it.remove();
            modified = true;
        }
    }
    return modified;
}

这里用图总结下,求交集的流程:

实现

1.『外层遍历+内层遍历』查找:

java中常用2种遍历查找的List:ArrayList、LinkedList,在内外层中测试。

// 外层:ArrayList,内层:ArrayList
private void outArrayListInnerArrayList(List<Long> listA, List<Long> listB) {
    long begin = System.currentTimeMillis();
    ArrayList<Long> setA = new ArrayList<>(listA);
    ArrayList<Long> setB = new ArrayList<>(listB);
    setA.retainAll(setB);
    long end = System.currentTimeMillis();
    System.out.println("[ArrayList-ArrayList]RetainAll耗时:" + (end - begin));
}

// 外层:LinkedList,内层:ArrayList
private void outLinkedListInnerArrayList(List<Long> listA, List<Long> listB) {
    long begin = System.currentTimeMillis();
    LinkedList<Long> setA = new LinkedList<>(listA);
    ArrayList<Long> setB = new ArrayList<>(listB);
    setA.retainAll(setB);
    long end = System.currentTimeMillis();
    System.out.println("[LinkedList-ArrayList]RetainAll耗时:" + (end - begin));
}

// 外层:ArrayList,内层:LinkedList
private void outArrayListInnerLinkedList(List<Long> listA, List<Long> listB) {
    long begin = System.currentTimeMillis();
    LinkedList<Long> setA = new LinkedList<>(listA);
    ArrayList<Long> setB = new ArrayList<>(listB);
    setA.retainAll(setB);
    long end = System.currentTimeMillis();
    System.out.println("[LinkedList-ArrayList]RetainAll耗时:" + (end - begin));
}

// 外层:LinkedList,内层:LinkedList
private void outLinkedListInnerLinkedList(List<Long> listA, List<Long> listB) {
    long begin = System.currentTimeMillis();
    LinkedList<Long> setA = new LinkedList<>(listA);
    ArrayList<Long> setB = new ArrayList<>(listB);
    setA.retainAll(setB);
    long end = System.currentTimeMillis();
    System.out.println("[LinkedList-LinkedList]RetainAll耗时:" + (end - begin));
}

2.『外层遍历+内层Hash』查找:

java中常用HashSet,内层替换为HashSet查找。

// 外层:
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值