Featured image of post 使用Map來找真的比List還快嗎

使用Map來找真的比List還快嗎

大膽假設,小心求證

這陣子工作上的時候又遇到一個要從兩個List中找出相同Id,然後 Assign 給對方的那種,正當我準備再寫個Double-ForEach來解決這個問題時,腦中突然被這種很醜的寫法給噁心到了,頓時間在想

「肯定有更好的方式吧」

於是就想到了HashMap,我知道取出Map的時間複雜度為O(1),但這是保證都是O(1)嗎?還是說只有用index查找,例如get(1)這種才快呢?老實說我不是很清楚,另外我如果要用HashMap,我勢必要先把List的內容put到Map中,那這樣跟我直接用Double-ForEach查找來講,是不是會更慢呢?於是今天打算來研究一下,我的想法很簡單,創造10,000,000個UID,並分別放到List跟Map,最後取出最後新增的UID,來比較兩者之間的速度

程式碼如下

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static void main(String[] args) {
        System.out.println("開始執行");
        HashMap<String, String> stringStringHashMap = new HashMap<>();
        List<String> uuidList = new ArrayList<>();
        String theLastUid="";
        long inputStartTime = System.currentTimeMillis();
        for(int i =0;i<10_000_000;i++){
            String uid = new UID().toString();
            stringStringHashMap.put(uid,uid);
            uuidList.add(uid);
            theLastUid=uid;
        }
        long inputEndTime = System.currentTimeMillis();
        System.out.println("資料塞完耗時" +(inputEndTime - inputStartTime));
        System.out.println("=======");
        long mapStartTime = System.currentTimeMillis();
        String mapString = stringStringHashMap.get(theLastUid);
        long mapEndTime = System.currentTimeMillis();
        System.out.println("Map耗時 :"+(mapEndTime - mapStartTime));
        System.out.println("Map撈出來的" + mapString);
        System.out.println("=======");
        long listStartTime = System.currentTimeMillis();
        String finalTheLastUid = theLastUid;
        String listString = uuidList.stream().filter(s -> s.equals(finalTheLastUid)).findFirst().orElse(null);
        long listEndTime = System.currentTimeMillis();
        System.out.println("List耗時 :"+(listEndTime - listStartTime));
        System.out.println("List撈出來的 = " + listString);
    }

最後輸出的結果

iShot_2024-06-20_23.08.46

1
2
3
4
5
6
7
8
開始執行
資料塞完耗時2228
=======
Map耗時 :0
Map撈出來的-122815f4:190363175b6:1717
=======
List耗時 :103
List撈出來的 = -122815f4:190363175b6:1717

沒想到Map查詢的速度居然是List的無限倍!那接下來我要驗證看看,Map雖然比較快,但是在塞資料這件事情上面,會不會Map消耗的時間比List還多,

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public static void main(String[] args) {
        System.out.println("開始執行");
        HashMap<String, String> stringStringHashMap = new HashMap<>();
        List<String> uuidList = new ArrayList<>();
        String theLastUid="";
        long inputStartTime = System.currentTimeMillis();
        for(int i =0;i<10_000_000;i++){
            String uid = new UID().toString();
            stringStringHashMap.put(uid,uid);
        }
        long inputEndTime = System.currentTimeMillis();
        System.out.println("Map資料塞完耗時" +(inputEndTime - inputStartTime));
        System.out.println("=======");

        long inputStartTime2 = System.currentTimeMillis();
        for(int i =0;i<10_000_000;i++){
            String uid = new UID().toString();
            uuidList.add(uid);
            theLastUid=uid;
        }
        long inputEndTime2 = System.currentTimeMillis();
        System.out.println("List資料塞完耗時" +(inputEndTime2 - inputStartTime2));
    }

iShot_2024-06-20_23.12.53

1
2
3
4
開始執行
Map資料塞完耗時2288
=======
List資料塞完耗時1656

可以看到我的想法確實沒錯,塞到hashMap確實比單純塞到List耗時還要長,因為還要處理哈希碰撞的問題,但相對來說,Map跟List塞進去的性能差異並沒有到搜尋的差異那麼大,而且這只是在只需要搜尋一次的場景,如果單一方法有需要搜尋兩次的話,那麼設定成Map確實是個不錯的解法。

Licensed under CC BY-NC-SA 4.0