想像一排火車車廂,每節只記得「下一節掛在哪」——這就是鏈結串列。它和陣列剛好互補:陣列像劃好位子的座位表,要在最前面塞一個人得整排往後挪;鏈結串列想插隊只要改一下「掛勾」就好,但要找第幾節就得從頭一節一節數過去。LRU Cache 則像容量有限的書桌,最近用的東西擺到手邊、桌子滿了就先收走最久沒碰的那樣。下面你會看到這兩種結構如何一步步改指標、把常用的東西留在手邊。
鏈結串列與動態陣列的取捨相反:陣列用「連續記憶體 + 索引」換來任意位置 O(1) 隨機存取,但頭部插入/刪除要整批搬移; 鏈結串列放棄隨機存取(找節點需沿指標走訪 O(n)),換來頭部插入/刪除只需改指標的 O(1)。 LRU Cache 則把兩種結構的長處疊在一起:HashMap 提供 O(1) 鍵定位,雙向鏈結提供 O(1) 的「移到最近使用端」與「淘汰最久未使用端」,兩者缺一都做不到整體 O(1)。
每個節點只存 value 與指向下一個節點的 next 指標;addFirst 只需改 head 指標為 O(1),addLast/insert/remove 都要先沿 next 走訪到目標位置的前一個節點才能改指標,故為 O(n)。reverse 逐節點把 next 反指向前一個節點(prev/curr/next 三指標迭代), 走訪中尚未換 head 前,被反轉的節點會暫時從 head 端不可達 —— 下方另闢一列如實呈現這段「已反轉部分」。
每個節點存 key/value,並以 head/tail 虛擬節點串成雙向鏈結:get 命中或 put 都會把節點 moveToHead 移到 MRU 端; put 新鍵若超過容量,淘汰 tail 端(LRU 端)的節點並自 hash 表移除。hash 表只負責「這個 key 對應哪個節點」的 O(1) 定位, 實際的「誰最近用過」順序完全交給雙向鏈結維護,兩者缺一都無法同時做到 O(1) 存取與 O(1) 淘汰。