iT邦幫忙

2026 iThome 鐵人賽

0
Build on Google AI

把Google AI當夥伴打造個人高效Coding工作流系列 第 15 篇

第十五天LinkedHashMap的LRU快取機制與TreeMap紅黑樹排序原理

  • 分享至 

  • xImage
  •  

一、 Map 家族的順序分流:無序 vs 插入序 vs 大小排序HashMap:完全無序。遍歷順序取決於 Hash 值分佈與陣列擴容後的桶位變化,無法保證順序穩定。LinkedHashMap:保證順序。在 HashMap 的基礎上額外維護一條全域雙向鏈結串列,可選擇「插入順序(Insertion-order)」或「存取順序(Access-order)」。TreeMap:大小排序(Sorted)。底層完全依賴紅黑樹(Red-Black Tree),根據 Key 的自然順序或傳入的 Comparator 進行排序,時間複雜度為穩定的 $O(\log N)$。


二、 LinkedHashMap 的底層架構與雙重結構

  1. 雙重結構的結合(Hash 表 + 雙向鏈結)
    LinkedHashMap 繼承自 HashMap,其節點 Entry<K, V> 繼承自 HashMap.Node,並額外增加了兩個指標:
    static class Entry<K,V> extends HashMap.Node<K,V> {
    Entry<K,V> before, after; // 維護整個 Map 元素的走訪鏈條
    Entry(int hash, K key, V value, Node<K,V> next) {
    super(hash, key, value, next);
    }
    }
    查詢時:利用 HashMap 的陣列與雜湊桶機制,維持 $O(1)$ 的高速定位。遍歷時:不再走訪整個稀疏的 HashMap 桶陣列,而是沿著 head 到 tail 的 before / after 雙向鏈結循序走訪,遍歷效能與實際元素個數($size$)成正比,不受 Bucket 容量大小影響。
  2. 兩種模式開關:accessOrder
    在建構子中有一個關鍵布林旗標:
    public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)
    accessOrder = false(預設值):依據插入順序(Insertion-order)維護鏈結。最先 put 的在最前面,遍歷時順序不變。
    accessOrder = true:依據存取順序(Access-order)維護鏈結。只要某個 Key 被 get() 或 put()(覆蓋更新),該節點就會自動被拔下來並移動到鏈結串列的最尾端(Tail)。

三、 實戰架構:利用 LinkedHashMap 實作 LRU 快取(Least Recently Used)
LRU(最近最少使用淘汰演算法)廣泛應用於系統快取設計。利用 LinkedHashMap 只要改寫一個鉤子方法(Hook Method)即可完成:

  1. 核心實作範例
    public class LruCache<K, V> extends LinkedHashMap<K, V> {
    private final int maxCapacity;

    public LruCache(int maxCapacity) {
    // 容量、負載因子、accessOrder 必須設為 true
    super(maxCapacity, 0.75f, true);
    this.maxCapacity = maxCapacity;
    }

    // 每次 put 元素後,HashMap 底層會呼叫此方法判斷是否需要移除最舊節點
    @Override
    protected boolean removeEldestEntry(Map.Entry<K, V> eldest) {
    return size() > maxCapacity;
    }
    }

  2. 淘汰流程運作原理:
    每次存取(get 或更新 put)現有元素時,節點自動移動至雙向鏈結的尾端(Tail,代表最新存取)。
    插入新節點時,若元素總數超過 maxCapacity,removeEldestEntry() 回傳 true。
    容器自動將位於雙向鏈結頭端(Head,代表最久未被存取的舊節點)徹底移除。


四、 TreeMap 的紅黑樹排序與契約限制

  1. 底層原理與特徵實作了 NavigableMap 與 SortedMap 介面,底層是一顆自平衡二元搜尋樹(紅黑樹)。查詢、新增、刪除操作的時間複雜度均為嚴格的 $O(\log N)$。提供強大的區間查詢能力:floorKey()、ceilingKey()、subMap() 等。

  2. 核心契約:比較器決定一切(不依賴 equals 與 hashCode)不使用 Hash:TreeMap 在判斷兩個 Key 是否相同時,完全不呼叫 equals() 或 hashCode(),而是依賴 Comparable.compareTo() 或傳入的 Comparator.compare()。

  • 唯一性判定標準:
    當 compare(key1, key2) == 0 時,TreeMap 即認定兩個 Key 相同,後者會覆蓋前者的 Value。
  • 陷阱警示:
    若自訂類別實作了 Comparable,請確保 compareTo == 0 與 equals == true 的邏輯嚴格一致。否則會出現「equals 判定不同,但在 TreeMap 裡卻被認定為同一筆並直接覆蓋」的資料遺失問題。
  1. Null Key 約束
    HashMap 允許放 null Key(固定存在桶 0)。

TreeMap 在使用自然排序時嚴禁使用 null 作為 Key,執行時會直接拋出 NullPointerException(因為呼叫 key.compareTo() 無法對 null 操作)。


上一篇
第十四天Set集合與equals/hashCode核心契約,物件屬性修改導致記憶體洩漏分析
下一篇
第十六天Collections工具類防禦陷阱、Arrays.asLis隱患與Java 9 List.of不可變集合
系列文
把Google AI當夥伴打造個人高效Coding工作流 共 18 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言