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存的就是交集

 

 原創分享,轉載標注。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM