【面試場景題】通過LinkedHashMap來實現LRU與LFU

文章目錄

      • 一、LRU與LFU的概念
        • 1. LRU(Least Recently Used,最近最少使用)
        • 2. LFU(Least Frequently Used,最不經常使用)
      • 二、LinkedHashMap的特性
      • 三、用LinkedHashMap實現LRU
        • 實現代碼:
        • 原理說明:
      • 四、用LinkedHashMap實現LFU
        • 實現代碼:
        • 原理說明:
      • 總結

一、LRU與LFU的概念

1. LRU(Least Recently Used,最近最少使用)

LRU是一種緩存淘汰策略,核心思想是:當緩存空間滿時,優先淘汰最久未被訪問的元素

  • 基于“最近使用的元素在未來更可能被再次使用”的假設。
  • 例如:緩存容量為3,訪問順序為A→B→C→A→D,當加入D時緩存滿,最久未被訪問的是B,因此淘汰B。
2. LFU(Least Frequently Used,最不經常使用)

LFU是另一種緩存淘汰策略,核心思想是:當緩存空間滿時,優先淘汰訪問次數最少的元素;若訪問次數相同,則淘汰最久未被訪問的元素

  • 基于“使用頻率高的元素在未來更可能被再次使用”的假設。
  • 例如:緩存容量為3,訪問次數:A(3次)、B(2次)、C(2次)(C比B更久未訪問),加入D時,B和C次數最少,淘汰更久未訪問的C。

二、LinkedHashMap的特性

LinkedHashMapHashMap 的子類,其核心特性是維護了一個雙向鏈表,記錄Entry的插入順序或訪問順序,這為實現LRU提供了天然支持。

  • 構造函數參數 accessOrdertrue 表示按訪問順序排序(每次get/put操作會將元素移到鏈表末尾);false(默認)表示按插入順序排序。
  • 方法 removeEldestEntry(Map.Entry<K,V> eldest):當此方法返回 true 時,LinkedHashMap 會自動刪除最老的Entry(鏈表頭部元素)。

三、用LinkedHashMap實現LRU

利用 LinkedHashMapaccessOrder=true 特性(訪問順序排序),配合重寫 removeEldestEntry 方法(當容量超限則刪除最老元素),即可實現LRU。

實現代碼:
import java.util.LinkedHashMap;
import java.util.Map;public class LRUCache<K, V> extends LinkedHashMap<K, V> {private final int capacity; // 緩存容量// 構造函數:指定容量、負載因子、訪問順序模式public LRUCache(int capacity) {super(capacity, 0.75f, true); // accessOrder=true:按訪問順序排序this.capacity = capacity;}// 重寫此方法:當Entry數量超過容量時,返回true,自動刪除最老元素@Overrideprotected boolean removeEldestEntry(Map.Entry<K, V> eldest) {return size() > capacity;}// 測試public static void main(String[] args) {LRUCache<Integer, String> cache = new LRUCache<>(3);cache.put(1, "A");cache.put(2, "B");cache.put(3, "C");System.out.println(cache); // {1=A, 2=B, 3=C}(插入順序)cache.get(1); // 訪問1,移到末尾System.out.println(cache); // {2=B, 3=C, 1=A}cache.put(4, "D"); // 容量超限,刪除最老元素2System.out.println(cache); // {3=C, 1=A, 4=D}}
}
原理說明:
  • accessOrder=true 確保每次訪問(getput)的元素被移到鏈表末尾(成為“最新”元素)。
  • 鏈表頭部始終是“最久未被訪問”的元素,當 size() > capacity 時,removeEldestEntry 返回 true,自動刪除頭部元素,實現LRU淘汰。

四、用LinkedHashMap實現LFU

LFU需要跟蹤元素的訪問次數,以及同次數下的最近訪問時間LinkedHashMap 本身不直接支持頻率排序,需結合額外結構輔助實現:

  1. Map<K, Integer> 記錄每個key的訪問次數(頻率)。
  2. Map<Integer, LinkedHashMap<K, V>> 按頻率分組:key為頻率,value為該頻率下的元素(按訪問順序排序,用于同頻率下淘汰最久未訪問元素)。
  3. 維護一個變量記錄當前最小頻率,方便快速找到需淘汰的組。
實現代碼:
import java.util.*;public class LFUCache<K, V> {private final int capacity; // 緩存容量private final Map<K, Integer> keyToFreq; // 記錄key的訪問次數private final Map<Integer, LinkedHashMap<K, V>> freqToEntries; // 按頻率分組,每組內按訪問順序排序private int minFreq; // 當前最小頻率public LFUCache(int capacity) {this.capacity = capacity;this.keyToFreq = new HashMap<>();this.freqToEntries = new HashMap<>();this.minFreq = 0;}// 獲取元素public V get(K key) {if (!keyToFreq.containsKey(key)) {return null;}// 1. 增加訪問頻率int oldFreq = keyToFreq.get(key);int newFreq = oldFreq + 1;keyToFreq.put(key, newFreq);// 2. 從舊頻率組中移除,加入新頻率組LinkedHashMap<K, V> oldEntries = freqToEntries.get(oldFreq);V value = oldEntries.remove(key);// 若舊頻率組為空,且是最小頻率,更新minFreqif (oldEntries.isEmpty()) {freqToEntries.remove(oldFreq);if (oldFreq == minFreq) {minFreq = newFreq;}}// 新頻率組不存在則創建(按訪問順序排序)freqToEntries.computeIfAbsent(newFreq, k -> new LinkedHashMap<>(capacity, 0.75f, true)).put(key, value);return value;}// 放入元素public void put(K key, V value) {if (capacity <= 0) return;// 若key已存在,先更新值并觸發get(更新頻率)if (keyToFreq.containsKey(key)) {freqToEntries.get(keyToFreq.get(key)).put(key, value); // 更新值get(key); // 觸發頻率更新return;}// 若緩存滿,淘汰最不經常使用的元素(最小頻率組中最老的)if (keyToFreq.size() >= capacity) {LinkedHashMap<K, V> minFreqEntries = freqToEntries.get(minFreq);// 移除最小頻率組中最老的元素(鏈表頭部)K eldestKey = minFreqEntries.keySet().iterator().next();minFreqEntries.remove(eldestKey);keyToFreq.remove(eldestKey);// 若最小頻率組為空,移除該組if (minFreqEntries.isEmpty()) {freqToEntries.remove(minFreq);}}// 新增元素:頻率為1,加入頻率1的組int newFreq = 1;keyToFreq.put(key, newFreq);freqToEntries.computeIfAbsent(newFreq, k -> new LinkedHashMap<>(capacity, 0.75f, true)).put(key, value);minFreq = newFreq; // 新元素頻率為1,最小頻率更新為1}// 測試public static void main(String[] args) {LFUCache<Integer, String> cache = new LFUCache<>(3);cache.put(1, "A"); // 頻率:1→{1:A},min=1cache.put(2, "B"); // 頻率:1→{1:A,2:B},min=1cache.put(3, "C"); // 頻率:1→{1:A,2:B,3:C},min=1cache.get(1); // 1的頻率變為2,min仍為1cache.get(1); // 1的頻率變為3,min仍為1cache.put(4, "D"); // 緩存滿,淘汰min=1中最老的2(1和2都在頻率1組,2更早未訪問)System.out.println(cache.get(2)); // null(已被淘汰)System.out.println(cache.get(1)); // A(存在)}
}
原理說明:
  • 頻率跟蹤keyToFreq 記錄每個key的訪問次數,每次 get/put 會更新頻率。
  • 分組管理freqToEntries 按頻率分組,每組用 LinkedHashMapaccessOrder=true)記錄元素,確保同頻率下最久未訪問的元素在鏈表頭部,便于淘汰。
  • 淘汰邏輯:當緩存滿時,找到最小頻率 minFreq,從對應組中移除最老元素(鏈表頭部),若組為空則移除該組并更新 minFreq

總結

策略核心邏輯LinkedHashMap的作用實現復雜度
LRU淘汰最久未訪問元素利用 accessOrder=true 維護訪問順序,重寫 removeEldestEntry 實現自動淘汰簡單
LFU淘汰訪問次數最少(同次數則最久未訪問)的元素作為頻率分組內的容器,維護同頻率元素的訪問順序較復雜(需額外結構跟蹤頻率)

LRU實現簡單、性能好,適合大多數場景;LFU更精準但實現復雜,適合對訪問頻率敏感的場景。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/918222.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/918222.shtml
英文地址,請注明出處:http://en.pswp.cn/news/918222.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第5章 Excel公式與函數應用指南(2):數學函數

5.2 數學函數 Excel作為強大的數據處理工具,其內置的數學函數體系為用戶提供了豐富的計算能力。從基礎的四則運算到復雜的指數對數計算,從簡單的數值舍入到專業的矩陣運算,Excel的數學函數幾乎可以滿足各類計算需求。 本節將重點為您解析七個常用且實用的數學函數:求和函…

mysql復制連接下的所有表+一次性拷貝到自己的庫

1.導出鏈接下的所有數據mysqldump -h 地址 -u 數據庫名 -p --all-databases --single-transaction --master-data2 > all_dbs.sql2.導入自己的庫mysql -h 127.0.0.1 -u root -p < all_dbs.sql3.指定導出某些庫mysqldump -u root -p --databases db1 db2 db3 > /path/t…

開發手札:UnrealEngine和Unity3d坐標系問題

最近把一套網絡模塊和一套組件模塊從u3d改造到ue4。網絡模塊通用性很高&#xff0c;畢竟協議都是通用網絡協議&#xff0c;改造后沒啥問題。但是改造組件模塊的時候就遇到了問題。首先&#xff0c;unity3d的坐標系是標準左手坐標系&#xff0c;如下&#xff1a;同時自己的幾何算…

QML 鼠標穿透

事件&#xff1a; 有一個輸入框(TextField)&#xff0c;需要實現鼠標懸浮時改變邊框顏色&#xff0c;鼠標移出后恢復原來邊框顏色&#xff1b; 這時如果需要實現此功能&#xff0c;就得使用到MouseArea&#xff0c;鼠標操作區域填充滿整個TextField。 然后實現鼠標移入移入出的…

VR 設備 PCB 怎樣憑借高頻材料達成高速傳輸

VR 設備的沉浸式體驗依賴于高分辨率圖像與低延遲交互&#xff0c;這要求設備內部數據傳輸速率達到 10Gbps 以上&#xff0c;而印制線路板&#xff08;PCB&#xff09;作為信號傳輸的核心載體&#xff0c;其材料性能直接決定傳輸效率。高頻材料憑借低介電常數&#xff08;Dk&…

Oracle字段操作

1. 新增字段 -- 新增字段 ALTER TABLE MES.WT_SUPPLEMENT_RECORD ADD (PAR_ATTR3 NUMBER DEFAULT NULL);2. 修改字段類型 -- 修改字段類型 ALTER TABLE MES.WT_SUPPLEMENT_RECORD MODIFY (PAR_ATTR3 VARCHAR2(32));3. 刪除字段 -- 刪除字段 ALTER TABLE MES.WT_SUPPLEMENT_RECO…

【原創】基于 Flask 的簡單文件收集器

在單位內網環境中&#xff0c;我經常需要收集 pdf 格式的記錄表。于是我基于 ai ide&#xff0c;開發了一個基于 Flask 開發的輕量級文件上傳服務項目&#xff0c;部署在單位飛騰芯的銀河麒麟系統上&#xff08;當然由于 python 的跨平臺&#xff0c;在 windows 和 mac 上也可部…

學習Java的Day28

今天在昨天完成的留言板項目基礎上&#xff0c;我進一步開發了一個酒店房型管理系統。該系統采用MVC架構&#xff0c;主要功能是對酒店房型信息進行增刪改查操作。數據庫設計方面&#xff0c;我創建了hotel_room_type表&#xff0c;包含以下字段&#xff1a;id&#xff1a;主鍵…

Leetcode——556. 下一個更大元素 III

題目鏈接&#xff1a;556. 下一個更大元素 III &#xff08;由于圖片上傳失敗&#xff0c;不貼原題目了&#xff0c;有需要可以前往力扣查看&#xff09; 本文給出該題的單調棧做法&#xff0c;同時繞過所有庫函數&#xff0c;所有邏輯均自行實現。 本題的思路就是從右向左按…

Idea打包可執行jar,MANIFEST.MF文件沒有Main-Class屬性:找不到或無法加載主類

背景&#xff1a;IDEA傳統方法【Project structure】-->artifact---->build的模式&#xff0c;打包【Maven】項目&#xff0c;發現生成的可執行jar包&#xff0c;顯示【找不到或無法加載主類】。但是用【Maven】的Assembly可以正常生成。期望用傳統方法實現打jar包方法&a…

檢索增強生成:RAG(Retrieval Augmented Generation)

什么是 RAG&#xff1f;為什么使用 RAG&#xff1f;LLM 微調 和 RAG&#xff1f;實戰什么是 RAG&#xff1f; RAG 在論文《Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks》中被引入&#xff0c;原論文是這樣描述的&#xff1a; 探索了一種 通用的 檢索增…

Android 設置/修改系統NTP服務地址

Android 手機的 NTP 時間同步&#xff08;網絡時間同步&#xff09;主要依賴網絡&#xff0c;但系統時間來源還包括其他方式&#xff0c;整體時間校準機制是多種來源的結合。具體可分為以下幾類&#xff1a; 1. 網絡 NTP 同步&#xff08;最主要方式&#xff09; 這是 Androi…

Ubuntu22.04 安裝vitis2023.2 卡在“Generating installed device list“.

關于這個問題&#xff0c;xilinx有官方說明&#xff0c;鏈接 原因&#xff1a;問題是 Ubuntu 20.04 缺少 libtinfo.so.5 庫。 解決辦法&#xff1a; sudo apt-get install libtinfo5

前端全棧修煉手冊:從 Vue3 到工程化的進階之路

本文將全方位覆蓋前端開發的核心知識&#xff0c;從 Vue3 框架的基礎語法到復雜的工程化實踐&#xff0c;從包管理工具的使用到模塊規范的深入理解&#xff0c;帶你踏上從入門到精通的進階之路。 Vue3 框架&#xff1a;新時代前端開發的基石 Vue3 核心語法探秘 Vue3 作為目前…

Jetpack Compose 常用控件

Jetpack Compose 常用控件一、基礎展示控件&#xff1a;呈現靜態內容二、交互控件&#xff1a;響應用戶操作三、列表與網格控件&#xff1a;展示大量數據四、導航與標簽控件&#xff1a;組織頁面結構五、反饋控件&#xff1a;提示與加載狀態六、布局控件&#xff1a;組織 UI 結…

Android適配最新SplashScreen方案:讓啟動頁不再“翻車“

Android適配最新SplashScreen方案:讓啟動頁不再"翻車" 各位開發者大佬們,最近是不是又被Android的SplashScreen適配搞得焦頭爛額?別慌,今天咱們就來聊聊這個讓人又愛又恨的啟動頁適配方案,保證讓你笑出腹肌的同時,還能把技術要點牢牢掌握![6][7][9][10] 一、…

【自動駕駛】《Sparse4Dv3》代碼學習筆記

這里時間比較有限&#xff0c;優先看Sparse4Dv3方法里面相對以前改動的地方。 0.參考 代碼v1/v2/v3:https://github.com/HorizonRobotics/Sparse4D 跑起來&#xff1a;https://github.com/HorizonRobotics/Sparse4D/blob/v3.0/docs/quick_start.md 1.方法 &#xff08;1&a…

「ECG信號處理——(22)Pan-Tompkins Findpeak 閾值檢測 差分閾值算法——三種R波檢測算法對比分析」2025年8月8日

目錄 1、引言 2、算法原理 &#xff08;1&#xff09;Pan-Tompkins 算法&#xff08;方法1&#xff09; &#xff08;2&#xff09;Findpeak 閾值檢測算法&#xff08;方法2&#xff09; &#xff08;3&#xff09;差分閾值算法&#xff08;方法3&#xff09; 3、算法性能…

Qdrant Filtering:must / should / must_not 全解析(含 Python 實操)

在向量搜索中&#xff0c;過濾&#xff08;Filtering&#xff09; 是保證結果精準性和業務契合度的關鍵手段。Qdrant 的過濾機制不僅能在向量相似度檢索的基礎上疊加結構化條件&#xff0c;還提供了靈活的布爾邏輯組合&#xff0c;讓我們可以像寫數據庫查詢一樣&#xff0c;精準…

五、RuoYi-Cloud-Plus 前端項目部署以及如何改后端請求地址。

1.前情描述 前面的文章我們介紹了RuoYi-Cloud-Plus的nocos的配置內容&#xff0c;已經啟動其他服務要注意什么東西。 專欄內容在這&#xff0c;感興趣可以看看。 https://blog.csdn.net/weixin_42868605/category_13023920.html 2.前端項目部署。 官網地址&#xff1a;plus…