• java遍历的优化


    说明:这是在面试中面试官出的题。虽然是常见的优化问题,但这种经验的确很有用。感慨之余,分享出来,以此共勉。

    场景:现有List<PersonA>,List<PersonB>,PersonA 的属性是 String类型的身份证号,int型age;PersonB 的属性是 String类型的身份证号,int型sex;两个集合中的身份证号有相同的;

    需求:查找身份证号相同的人的性别。

    常见的思路是:

     1 @Data
     2 public class PersonA {
     3     private String card;
     4     private int age;
     5 
     6     public PersonA(String card, int age) {
     7         this.card = card;
     8         this.age = age;
     9     }
    10 }
    11 ----------------------------------------------
    12 @Data
    13 public class PersonB {
    14     private String card;
    15     private int sex;
    16 
    17     public PersonB(String card, int sex) {
    18         this.card = card;
    19         this.sex = sex;
    20     }
    21 }

    public class TestForFor {
        private List<PersonA> pa;
        private List<PersonB> pb;
        @Before
        public void before(){
            pa = new ArrayList<>();
            for (int i = 0; i < 10000; i++) {
                pa.add(new PersonA(UUID.randomUUID().toString(),20));
            }
            pa.add(new PersonA("abcd111",10));
            pa.add(new PersonA("abcd112",10));
            pa.add(new PersonA("abcd113",10));
            pa.add(new PersonA("abcd114",10));
            pa.add(new PersonA("abcd115",10));
            pa.add(new PersonA("abcd116",10));
            pb = new ArrayList<>();
            for (int i = 0; i < 10000; i++) {
                pb.add(new PersonB(UUID.randomUUID().toString(),Math.random() >= 0.5 ? 1 : 0));
            }
            pb.add(new PersonB("abcd111",1));
            pb.add(new PersonB("abcd112",1));
            pb.add(new PersonB("abcd113",1));
            pb.add(new PersonB("abcd114",1));
            pb.add(new PersonB("abcd115",1));
            pb.add(new PersonB("abcd116",1));
        }
        @Test
        public void testFor(){
            out.println("start search");
            for (PersonA a : pa) {
                for (PersonB b : pb) {
                     if (a.getCard().equals(b.getCard())){
                         out.println(b.getSex()==1?"男":"女");
                     }
                }
            }
        }
    }

    结果。。。花费三秒多的时间。这还只是一万条数据

    现在换一种思路,直接贴代码

     1  private List<PersonA> pa;
     2     private List<PersonB> pb;
     3     private Map<String,Object> map;
     4     @Before
     5     public void before(){
     6         out.println("start before");
     7         pa = new ArrayList<>();
     8         for (int i = 0; i < 10000; i++) {
     9             pa.add(new PersonA(UUID.randomUUID().toString(),20));
    10         }
    11         pa.add(new PersonA("abcd111",10));
    12         pa.add(new PersonA("abcd112",10));
    13         pa.add(new PersonA("abcd113",10));
    14         pa.add(new PersonA("abcd114",10));
    15         pa.add(new PersonA("abcd115",10));
    16         pa.add(new PersonA("abcd116",10));
    17 
    18 
    19         pb = new ArrayList<>();
    20         for (int i = 0; i < 10000; i++) {
    21             pb.add(new PersonB(UUID.randomUUID().toString(),Math.random() >= 0.5 ? 1 : 0));
    22         }
    23         pb.add(new PersonB("abcd111",1));
    24         pb.add(new PersonB("abcd112",1));
    25         pb.add(new PersonB("abcd113",1));
    26         pb.add(new PersonB("abcd114",1));
    27         pb.add(new PersonB("abcd115",1));
    28         pb.add(new PersonB("abcd116",1));
    29         map = new HashMap<>();
    30         for ( PersonB pbb : pb ) {
    31             map.put(pbb.getCard(),pbb.getSex());
    32         }
    33     }
    34     @Test
    35     public void testFor(){
    36         out.println("start search");
    37         for (PersonA a : pa) {
    38             if (map.containsKey(a.getCard())){
    39                 out.print(a.getAge()+" ");
    40                 out.println((int)map.get(a.getCard())==1?"男":"女");
    41             }
    42             //out.println(map.get(a.getCard())==null?"空":map.get(a.getCard()));
    43             //out.println((int)map.get(a.getCard())==1?"男":"女");
    44         }
    45     }

    可以看出,查找的效率明显提升。

    这里面的重点,第29行我用map重新填写了pb的数据[我的本地的sql坏了,所以用伪数据库的方式模仿,感兴趣也可以从数据库里试试],

    为什么用map填完了后速度会这么快?

    原因很简单。因为ArrayList的底层是数组实现的,若要查找必定是从索引0开始一个个的进行比对;而HashMap则不同,

    HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的,如果定位到的数组位置不含链表(当前entry的next指向null),那么对于查找,添加等操作很快,仅需一次寻址即可;如果定位到的数组包含链表,对于添加操作,其时间复杂度依然为O(1),因为最新的Entry会插入链表头部,仅需要简单改变引用链即可,而对于查找操作来讲,此时就需要遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。

    关于以上加粗内容取自博客

    我在面试时只想到了hash,面试官提醒我用hashmap,恍然大悟。


    时隔数月,回来归纳下这个问题。2018/9/13


    其实这个问题可以抽象为:两个数组求交集,这里简要说下思路。

    使用 treeset装载第一个数组,遍历第二个数组,if(!contains数组二中的值),add到一个新list中,最后这个list存的就是交集

     原创分享,转载标注。

  • 相关阅读:
    2015.7.23 开始记录一些学习情况
    poj 3299 java
    在线编辑~
    MATLAB加载数据来绘图《原创翻译Loading Data into MATLAB for Plotting》
    【转载】matlab的reshape函数的作用
    (转载)CUDA 6.0 安装及配置( WIN7 64位 / 英伟达G卡 / VS2010 )
    简单文本处理
    【转】CUDA与二维动态数组
    《转载》 cpp文件调用CUDA .cu文件实现显卡加速相关编程
    cuda_opencv之向量相加
  • 原文地址:https://www.cnblogs.com/woooodlin/p/8506289.html
Copyright © 2020-2023  润新知