最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中自定義LRU緩存詳解

 更新時(shí)間:2023年09月21日 10:45:52   作者:曉之木初  
這篇文章主要介紹了Java中自定義LRU緩存詳解,基于LRU算法的緩存系統(tǒng),可以在達(dá)到緩存容量上限時(shí),清理最近最少使用的數(shù)據(jù),為新的數(shù)據(jù)的插入騰出空間,需要的朋友可以參考下

1. LRU算法

  • 在計(jì)算機(jī)領(lǐng)域,LRU算法的應(yīng)用非常多,最常見的就是LRU緩存
  • LRU:Least Recently USed,最近最少使用
  • 英文和中文存在差異,如果只看中文,貌似RLU更合適
  • 基于LRU算法的緩存系統(tǒng),可以在達(dá)到緩存容量上限時(shí),清理最近最少使用的數(shù)據(jù),為新的數(shù)據(jù)的插入騰出空間
  • leetcode上,也有對(duì)應(yīng)的LRU緩存算法題:146. LRU 緩存機(jī)制
  • ??蜕?,螞蟻金服的面試題庫,LRU緩存也赫然在列
  • 題目要求大概如下:
    • 設(shè)計(jì)和實(shí)現(xiàn)一個(gè)LRU算法的緩存數(shù)據(jù)結(jié)構(gòu)。需要實(shí)現(xiàn)兩個(gè)操作:get和set
    • 獲取數(shù)據(jù) get(key) :如果關(guān)鍵字 (key) 存在于緩存中,則獲取關(guān)鍵字的值(總是正數(shù)),否則返回 -1。
    • 寫入數(shù)據(jù) put(key, value) :
      • 如果關(guān)鍵字已經(jīng)存在,則變更其數(shù)據(jù)值;
      • 如果關(guān)鍵字不存在,則插入該組<key, value>。
      • 當(dāng)緩存容量達(dá)到上限時(shí),它應(yīng)該在寫入新數(shù)據(jù)之前刪除最久未使用的數(shù)據(jù)值,從而為新的數(shù)據(jù)值留出空間。

2. 繼承LinkedHashMap實(shí)現(xiàn)LRU緩存

通過對(duì)LinkedHashMap的學(xué)習(xí),我們了解到:

與HashMap不同,LinkedHashMap作為鏈表形式的哈希表,支持元素的插入順序或訪問順序

使用訪問順序時(shí),通過重寫removeEldestEntry()方法,可以刪除最近最少使用的鍵值對(duì)

因此,可以通過繼承LinkedHashMap、重寫removeEldestEntry() 方法,實(shí)現(xiàn)LRU緩存

import java.util.LinkedHashMap;
import java.util.Map;
public class LRUCache extends LinkedHashMap<Integer, Integer> {
    private int capacity;
    public LRUCache(int capacity) {
        // true表示按訪順序存儲(chǔ)鍵值對(duì),最近訪問的在尾部,最近最少訪問在頭部
        super(capacity, 0.75f, true);
        this.capacity = capacity;
    }
    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
        return size() > capacity;
    }
    public int get(int key) {
        // 根據(jù)題目要求,不存在key時(shí),不能直接返回null值,而是需要返回默認(rèn)值-1
        return super.getOrDefault(key, -1);
    }
    public void put(int key, int value) {
        super.put(key, value);
    }
}

3. 自定義LRU緩存

  • 如果在面試時(shí),碰到該題,應(yīng)該先和面試官確認(rèn),是否能使用現(xiàn)成的數(shù)據(jù)結(jié)構(gòu)去實(shí)現(xiàn)
  • 如果面試官明確要求說,需要自己去實(shí)現(xiàn)LRU緩存,不能使用現(xiàn)成的數(shù)據(jù)結(jié)構(gòu),那么時(shí)候展現(xiàn)你的實(shí)力了

最原始的想法:

  • 既然LinkedHashMap都是雙向鏈表 + HashMap實(shí)現(xiàn)的,那我自己定義一個(gè)雙向鏈表實(shí)現(xiàn)類似的功能
class DLinkedNode{
    private int key;
    private int val;
    private DLinkNode prev;
    private DLinkNode next;
}
  • 基于雙向鏈表,可以在 O ( 1 ) O(1) O(1)的時(shí)間內(nèi)快速增加、刪除節(jié)點(diǎn)
  • 但在確定節(jié)點(diǎn)位置時(shí),需要從頭到尾遍歷鏈表
  • 就算使用雙指針左右開弓,在定位節(jié)點(diǎn)時(shí),依然存在很大的開銷

思路進(jìn)階

  • 借助HashMap,以O(shè) ( 1 ) O(1)O(1)的時(shí)間復(fù)雜度快速get或put數(shù)據(jù)
  • 同時(shí),規(guī)定:最近訪問的節(jié)點(diǎn)放在鏈表的頭部,最近最少訪問的節(jié)點(diǎn)放在鏈表的尾部
  • 如果頭部或尾部直接存儲(chǔ)數(shù)據(jù),則在實(shí)現(xiàn)時(shí)需要考慮節(jié)點(diǎn)是否為頭節(jié)點(diǎn)或尾結(jié)點(diǎn)的情況
  • 因此,直接創(chuàng)建dummy的head和tail節(jié)點(diǎn),以減少編寫代碼的工作量

最終的代碼實(shí)現(xiàn)

通過上述分析,代碼如下

import java.util.HashMap;
public class LRUCache{
    private HashMap<Integer, DLinkedNode> map;
    private DLinkedNode head;
    private DLinkedNode tail;
    private int capacity;
    private int size;
    public LRUCache(int capacity) {
        this.capacity = capacity;
        map = new HashMap<>();
        // 初始化帶dummy節(jié)點(diǎn)的雙向鏈表
        head = new DLinkedNode();
        tail = new DLinkedNode();
        head.next = tail;
        tail.prev = head;
    }
    public int get(int key) {
        DLinkedNode node = map.get(key);
        if (node == null) {
            return -1;
        }
        // 被訪問,需要從當(dāng)前位置移動(dòng)到頭部
        if (head.next != node){
            removeNode(node);
            insertToHead(node);
        }
        return node.val;
    }
    public void put(int key, int value) {
        DLinkedNode node = map.get(key);
        // 如果存在,直接更新值
        if (node != null) {
            node.val = value;
            // 被訪問,需要從當(dāng)前位置移動(dòng)到頭部
            if (head.next != node) {
                removeNode(node);
                insertToHead(node);
            }
        } else {
            // 插入前,先判斷是否需要騰出空間
            if (size == capacity) {
                // 從鏈表中刪除尾結(jié)點(diǎn)
                DLinkedNode last = tail.prev;
                removeNode(last);
                // 從map中移除記錄
                map.remove(last.key);
                size--;
            }
            // 新建節(jié)點(diǎn)并插入
            DLinkedNode newNode = new DLinkedNode(key, value);
            insertToHead(newNode);
            map.put(key, newNode);
            size++;
        }
    }
    // 插入節(jié)點(diǎn)一定是在頭部
    public void insertToHead(DLinkedNode node) {
        // 分別建立與head.next和head的關(guān)聯(lián)
        DLinkedNode next = head.next;
        node.next = next;
        next.prev = node;
        head.next = node;
        node.prev = head;
    }
    // 刪除指定節(jié)點(diǎn)
    public void removeNode(DLinkedNode node) {
        DLinkedNode prev = node.prev;
        DLinkedNode next = node.next;
        prev.next = next;
        next.prev = prev;
        // 斷開引用,幫助GC
        node.prev = null;
        node.next = null;
    }
}
class DLinkedNode{
     int key;
     int val;
     DLinkedNode prev;
     DLinkedNode next;
    public DLinkedNode() {
    }
    public DLinkedNode(int key, int val) {
        this.key = key;
        this.val = val;
    }
}

幾點(diǎn)注意事項(xiàng):

  • 節(jié)點(diǎn)移動(dòng)到頭部情況:get時(shí),節(jié)點(diǎn)被訪問;put時(shí),節(jié)點(diǎn)的值被更新。put時(shí)的情況,容易被忽略
  • 新增節(jié)點(diǎn)時(shí),按照題目要求是先刪除最久未使用的節(jié)點(diǎn),并非先插入再刪除
  • 注意雙向鏈表和HashMap的聯(lián)動(dòng),刪除或新增節(jié)點(diǎn),HashMap中也要?jiǎng)h除或新增記錄

到此這篇關(guān)于Java中自定義LRU緩存詳解的文章就介紹到這了,更多相關(guān)Java的LRU緩存內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • springcloud gateway如何配置動(dòng)態(tài)路由

    springcloud gateway如何配置動(dòng)態(tài)路由

    本文主要介紹了在SpringCloudGateway中配置動(dòng)態(tài)路由的步驟,包括引入依賴、配置路由源、添加配置中心依賴、配置配置中心、定義路由規(guī)則和刷新配置等內(nèi)容,使路由規(guī)則在配置中心更新時(shí),無需重啟網(wǎng)關(guān)服務(wù)即可動(dòng)態(tài)應(yīng)用新的路由規(guī)則
    2024-10-10
  • 微信小程序完整項(xiàng)目實(shí)戰(zhàn)記錄(前端+SpringBoot后端)

    微信小程序完整項(xiàng)目實(shí)戰(zhàn)記錄(前端+SpringBoot后端)

    隨著微信小程序的流行,越來越多的開發(fā)者開始涉足小程序開發(fā),下面這篇文章主要給大家介紹了關(guān)于微信小程序完整項(xiàng)目實(shí)戰(zhàn)的相關(guān)資料,項(xiàng)目包括前端+SpringBoot后端,需要的朋友可以參考下
    2024-09-09
  • Android圖片轉(zhuǎn)換器代碼分享

    Android圖片轉(zhuǎn)換器代碼分享

    本文給大家總結(jié)了下在安卓程序中進(jìn)行圖片轉(zhuǎn)換的方法,非常的實(shí)用,小伙伴們可以參考下。
    2015-10-10
  • Java 十大排序算法之選擇排序刨析

    Java 十大排序算法之選擇排序刨析

    選擇排序是一種簡單直觀的排序算法,無論什么數(shù)據(jù)進(jìn)去都是 O(n&sup2;) 的時(shí)間復(fù)雜度。所以用到它的時(shí)候,數(shù)據(jù)規(guī)模越小越好。唯一的好處可能就是不占用額外的內(nèi)存空間了吧
    2021-11-11
  • Java List中數(shù)據(jù)的去重

    Java List中數(shù)據(jù)的去重

    今天小編就為大家分享一篇關(guān)于Java List中數(shù)據(jù)的去重,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2019-01-01
  • SpringBoot項(xiàng)目打包成war包并部署在tomcat上運(yùn)行的操作步驟

    SpringBoot項(xiàng)目打包成war包并部署在tomcat上運(yùn)行的操作步驟

    我們開發(fā) SpringBoot 項(xiàng)目有時(shí)我們會(huì)需要打包成 war 包,放入外置的 Tomcat 中進(jìn)行運(yùn)行,或者使用工具idea直接啟動(dòng),便于開發(fā)調(diào)試,本文給大家分享SpringBoot項(xiàng)目打包成war包并部署在tomcat上運(yùn)行的操作步驟,感興趣的朋友一起看看吧
    2024-03-03
  • java中List<String>轉(zhuǎn)字符串形式常用方法總結(jié)(非常全!)

    java中List<String>轉(zhuǎn)字符串形式常用方法總結(jié)(非常全!)

    這篇文章主要介紹了java中List<String>轉(zhuǎn)字符串形式的相關(guān)資料,文中通過示例總結(jié)了五種字符串連接方法及進(jìn)階場景、性能優(yōu)化與特殊字符處理技巧,需要的朋友可以參考下
    2025-05-05
  • Android中Parcelable的作用實(shí)例解析

    Android中Parcelable的作用實(shí)例解析

    這篇文章主要介紹了Android中Parcelable的作用,對(duì)于Android初學(xué)者有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2014-08-08
  • spring mvc靜態(tài)資源權(quán)限訪問的設(shè)置方式

    spring mvc靜態(tài)資源權(quán)限訪問的設(shè)置方式

    文章描述了在Spring MVC項(xiàng)目中,controller層和jsp頁面交互時(shí),因未開放靜態(tài)資源訪問導(dǎo)致數(shù)據(jù)提交異常,通過在spring-mvc配置文件中開放靜態(tài)資源訪問,成功解決了問題,控制臺(tái)可正常接收到ajax提交的json數(shù)據(jù)
    2025-10-10
  • Java通過SSH連接路由器輸入命令并讀取響應(yīng)的操作方法

    Java通過SSH連接路由器輸入命令并讀取響應(yīng)的操作方法

    最近需要讀取和修改華為路由器的配置,使用Java語言開發(fā),通過SSH連接,輸入命令并讀取響應(yīng),接下來通過本文給大家介紹下Java通過SSH連接路由器,輸入命令并讀取響應(yīng),需要的朋友可以參考下
    2024-01-01

最新評(píng)論

同江市| 息烽县| 临清市| 诸暨市| 余姚市| 淳安县| 泾川县| 嘉荫县| 南汇区| 金堂县| 邯郸县| 温宿县| 密山市| 龙川县| 老河口市| 叙永县| 安庆市| 永嘉县| 屏边| 永登县| 宝清县| 尖扎县| 遵义市| 额尔古纳市| 婺源县| 枣强县| 八宿县| 胶州市| 中西区| 九寨沟县| 招远市| 山西省| 博乐市| 沙坪坝区| 宁津县| 手机| 咸宁市| 山西省| 连云港市| 太白县| 鸡东县|