• removeAll


    Java中,List是最常用到的一种集合类。我们也经常对List进行操作,也没有碰到什么问题。但是刚刚在调用removeAll方法是,碰到了严重的性能问题。

    问题是这样的:

    原集合:List<T> source,有大概200,000数据。

    目标集合:List<T> destination,有大概150,000数据。

    两者中都可能有重复的元素,两者中可能有相同的元素。已经实现了T中的hashCode(),equals()方法。我调用了source.removeAll(destination),结果花费了15分钟时间。这真是不可接受的。

    下来就是自己瞎折腾,试图实现一个与removeAll()方法功能一样的方法,但是性能要有提高。

    思路一:有资料表明,给List中add()数据的速度要比从List中remove()数据的快。试着实现了下,但是效果不明显,与原来的removeAll()差别不大。源代码如下:

    [html] view plain copy
     
    1. public List<T> removeAll_01(List<T> source, List<T> destination) {  
    2.     List<Tresult = new LinkedList<T>();  
    3.     for(T t : source) {  
    4.         if (!destination.contains(t)) {  
    5.             result.add(t);  
    6.         }  
    7.     }  
    8.     return result;  
    9. }  

    思路二:运用Set可以去重这一特性。将source中的元素逐个添加到由destination生成的Set中,如果Set.add(e)为true,说明e应该保留到结果中,否则放弃e。因为source中可能存在重复的元素,因此想到用Map来保存source中的元素与其在source中出现的次数。结果令我大跌眼镜,太JB帅了。性能的提高有好几个数量级。源代码如下:

    [html] view plain copy
     
    1. public List<T> removeAll_02(List<T> source, List<T> destination) {  
    2.     List<Tresult = new LinkedList<T>();  
    3.   
    4.     Map<T, IntegersourceMap = new HashMap<T, Integer>();  
    5.     for (T t : source) {  
    6.         if (sourceMap.containsKey(t)) {  
    7.             sourceMap.put(t, sourceMap.get(t) + 1);  
    8.         } else {  
    9.             sourceMap.put(t, 1);  
    10.         }  
    11.     }  
    12.   
    13.     Set<Tall = new HashSet<T>(destination);  
    14.     for (Map.Entry<T, Integer> entry : sourceMap.entrySet()) {  
    15.         T key = entry.getKey();  
    16.         Integer value = entry.getValue();  
    17.         if (all.add(key)) {  
    18.             for (int i = 0; i value; i++) {  
    19.                 result.add(key);  
    20.             }  
    21.         }  
    22.     }  
    23.     return result;  
    24. }  

    思路三:比较下思路二和思路一的代码实现,思路二优于思路一?为什么,为什么?难道Map.containsKey()方法要比List.contains()方法快几何倍数。所以有了思路三。因为Map.containsKey()实际就是Set.contains(),所以对思路一的代码做了少许修改。证实了想法,结果比思路二更好。源代码如下:

    [html] view plain copy
     
    1. public List<T> removeAll_03(List<T> source, List<T> destination) {  
    2.     List<Tresult = new LinkedList<T>();  
    3.     Set<TdestinationSet = new HashSet<T>(destination);  
    4.     for(T t : source) {  
    5.         if (!destinationSet.contains(t)) {  
    6.             result.add(t);  
    7.         }  
    8.     }  
    9.     return result;  
    10. }  

    那么,让我没看看具体的下效果如何。为了方便测试,T选用Integer,List中的元素用随机数Random.nextInt(),随机数的最大之为1,000,000。

    上述结果表明,随着数据量的变大,思路二和思路三的表现非常出色。为什么会这样呢?归根到底,还是因为Map.containsKey()和Set.contains()的速度快。

  • 相关阅读:
    冒泡排序
    线程同步
    线程取消
    线程分离
    第3月第2天 find symbolicatecrash 生产者-消费者 ice 引用计数
    第3月第1天 GCDAsyncSocket dispatch_source_set_event_handler runloop
    第2月第25天 BlocksKit
    第2月第24天 coretext 行高
    第2月第6天 iOS 运行时添加属性和方法
    第2月第5天 arc invocation getReturnValue
  • 原文地址:https://www.cnblogs.com/pureEve/p/6553428.html
Copyright © 2020-2023  润新知