【设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构】

这篇具有很好参考价值的文章主要介绍了【设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构】。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。


一、什么是LRU?

LRU是Least Recently Used的缩写,意为最近最少使用。它是一种缓存淘汰策略,用于在缓存满时确定要被替换的数据块。LRU算法认为,最近被访问的数据在将来被访问的概率更高,因此它会优先淘汰最近最少被使用的数据块,以给新的数据块腾出空间。

如图所示:

【设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构】,缓存,数据结构,java,算法

  1. 先来3个元素进入该队列
    【设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构】,缓存,数据结构,java,算法

  2. 此时来了新的元素,因为此时队列中每个元素的使用的次数都相同(都是1),所以会按照LFU的策略淘汰(即淘汰掉最老的那个)
    【设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构】,缓存,数据结构,java,算法

  3. 此时又来了新的元素,而且是队列是已经存在的,就会将该元素调整为最新的位置。
    【设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构】,缓存,数据结构,java,算法

  4. 如果此时又来了新的元素,还是”咯咯“,由于”咯咯“已经处于最新的位置,所以大家位置都不变。
    【设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构】,缓存,数据结构,java,算法

  5. 同理,一直进行上述的循环


二、LinkedHashMap 实现LRU缓存

以力扣的算法题为例子:


力扣146. LRU 缓存


在 jdk 官方的介绍中可以看出,该数据结构天生适合实现 LRU。

【设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构】,缓存,数据结构,java,算法

代码示例一:


/**
 * 利用继承 LinkedHashMap 的方式实现LRU缓存
 */


class LRUCache extends LinkedHashMap<Integer, Integer> {
	// 缓存容量
    private int capacity;

    public LRUCache(int capacity) {
    	// 初始化
        super(capacity, 0.75f, true);
        this.capacity = capacity;
    }
    
    public int get(int key) {
        return super.getOrDefault(key, -1);
    }
    
    public void put(int key, int value) {
        super.put(key, value);
    }

    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
    	// 重写比较方法
        return super.size() > capacity;
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

代码示例二:

/**
 * 利用 LinkedHashMap 特点的方式实现LRU缓存
 */
 
class LRUCache {
   // 额定容量
    private final int CAPACITY;
    // 使用 LinkedHashMap 的有序排重特点达到要求
    private final Map<Integer, Integer> map;


    public LRUCache(int capacity) {
        // 初始化
        CAPACITY = capacity;
        map = new LinkedHashMap<>(CAPACITY);
    }

    public int get(int key) {
        Integer value = map.get(key);
        if (value != null) {// 存在
            // 1. 先删除旧的
            map.remove(key);
            // 2. 再添加回去,同时更新了 key 的位置和 value
            map.put(key, value);
            // 3. 返回结果
            return value;
        } else {// 不存在
            return -1;
        }
    }

    public void put(int key, int value) {
        if (map.size() == CAPACITY) {// 达到最大容量
            if (!map.containsKey(key)) {// 不存在,就删除头
                Integer head = map.keySet().iterator().next();
                map.remove(head);
            } else {// 存在,就删除自身
                map.remove(key);
            }
        } else {// 还有剩余空间,删除自身
            map.remove(key);
        }
        // 添加新的或 key 更新后的 value
        map.put(key, value);
    }
}



三、手写LRU

代码示例如下:文章来源地址https://www.toymoban.com/news/detail-810791.html

/**
 * https://leetcode.cn/problems/lru-cache/description/
 * 手写 LRU 缓存
 * Map + 双向链表
 */
class LRUCache {
    // Map 负责查找,构建一个虚拟的双向链表,它里面安装的就是一个个 Node 节点,作为数据载体。

    // 参考 HashMap 中的存储方式,使用内部 Node 维护双向链表
    // 1. 构造 Node 节点作为数据载体
    public static class Node<K, V> {
        public K key;
        public V value;
        public Node<K, V> prev;
        public Node<K, V> next;

        public Node() {
            this.prev = this.next = null;
        }

        public Node(K key, V value) {
            this.key = key;
            this.value = value;
            this.prev = this.next = null;
        }
    }

    // 2. 构造一个双向队列,里面存放着 Node 节点
    // 队头元素最新,队尾元素最旧
    static class DoubleLinkedList<K, V> {
        Node<K, V> head;
        Node<K, V> tail;

        // 2.1 构造方法
        public DoubleLinkedList() {
            head = new Node<>();
            tail = new Node<>();
            // 头尾相连
            head.next = tail;
            tail.prev = head;
        }

        // 2.2 添加到头(头插)
        public void addHead(Node<K, V> node) {
            node.next = head.next;
            node.prev = head;
            head.next.prev = node;
            head.next = node;
        }

        // 2.3 删除节点
        public void removeNode(Node<K, V> node) {
            node.next.prev = node.prev;
            node.prev.next = node.next;
            node.next = null;
            node.prev = null;
        }

        // 2.4 获取最后一个节点
        public Node getLast() {
            return tail.prev;
        }
    }

    private final int cacheSize;
    Map<Integer, Node<Integer, Integer>> map;// Map
    DoubleLinkedList<Integer, Integer> doubleLinkedList;// 双向链表


    public LRUCache(int capacity) {
        this.cacheSize = capacity;
        map = new HashMap<>();
        doubleLinkedList = new DoubleLinkedList<>();
    }
    
    public int get(int key) {
        if (map.containsKey(key)) {
            // 命中,更新双向链表
            Node<Integer, Integer> node = map.get(key);
            // 先删除双向链表中的节点
            doubleLinkedList.removeNode(node);
            // 再添加到头部
            doubleLinkedList.addHead(node);
            return node.value;
        } else {
            // 未命中,返回 -1
            return -1;
        }
    }
    
    public void put(int key, int value) {
        if (map.containsKey(key)) {
            // 更新双向链表
            Node<Integer, Integer> node = map.get(key);
            // 新值替换老值,再放回
            node.value = value;
            map.put(key, node);
            // 先删除双向链表中的节点
            doubleLinkedList.removeNode(node);
            // 再添加到头部
            doubleLinkedList.addHead(node);
        } else {
            if (map.size() == cacheSize) {
                // 超出容量,删除双向链表的最后一个节点
                Node lastNode = doubleLinkedList.getLast();
                map.remove(lastNode.key);
                doubleLinkedList.removeNode(lastNode);
            }
            // 新增节点
            Node<Integer, Integer> newNode = new Node<>(key, value);
            map.put(key, newNode);
            doubleLinkedList.addHead(newNode);
        }
    }
}


到了这里,关于【设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构】的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 孩子都能学会的FPGA:第二十八课——用FPGA实现最近最少使用(LRU)算法

    (原创声明:该文是 作者的原创 ,面向对象是 FPGA入门者 ,后续会有进阶的高级教程。宗旨是 让每个想做FPGA的人轻松入门 , 作者不光让大家知其然,还要让大家知其所以然 !每个工程作者都搭建了全自动化的仿真环境,只需要双击 top_tb.bat 文件就可以完成整个的仿真(前

    2024年02月19日
    浏览(34)
  • rust里如何快速实现一个LRU 本地缓存?

    LRU是Least Recently Used(最近最少使用)的缩写,是一种常见的缓存淘汰算法。LRU算法的基本思想是,当缓存空间已满时,优先淘汰最近最少使用的数据,以保留最常用的数据。 在计算机系统中,LRU算法常用于缓存系统、页面置换算法等场景,以提高数据访问的效率和性能。 要

    2024年02月13日
    浏览(32)
  • verilog实例-近期最少使用算法(LRU)

    LRU算法 用于cache管理或任何其他需要对访问权进行周期更新的场合。 基于时间和空间考虑,cache中存储着近期将会用到的数据项。当cache被用满后,如果有新的数据项到来,需要将某个现有的数据项从cache中清除,为新进入者提供空间。此时通常使用的算法被称为LRU(Least Rece

    2024年02月08日
    浏览(38)
  • 二维网格划分 LRU缓存设计

    有大量的二维矩形需要存储 查看点在哪些矩形中 给定一个矩形 查看与哪些矩阵相交 项目背景与图形图像基本无关,只涉及大文件分块读取,所以不用实现游戏行业中的物理引擎 使用空间划分算法:二维栅格将整个空间划分为多个小区域。每个小区域中包含若干个矩形,以

    2024年02月14日
    浏览(23)
  • 【算法训练-模拟 一】模拟设计LRU缓存结构

    废话不多说,喊一句号子鼓励自己:程序员永不失业,程序员走向架构!本篇Blog的主题是LRU缓存结构设计,这类题目出现频率还是很高的,几乎所有大厂都常考。 当然面对这道题,首先要讲清楚LRU是干什么的 LRU(Least Recently Used)缓存结构是一种常见的缓存管理策略, 用于

    2024年02月10日
    浏览(34)
  • 【数据结构】LRU缓存的简单模拟实现(leetcode力扣146LRU缓存)

    LRU是Least Recently Used的缩写,意思是最近最少使用,它是一种Cache替换算法。 Cache的容量有限,因此当Cache的容量用完后,而又有新的内容需要添加进来时, 就需要挑选并舍弃原有的部分内容,从而腾出空间来放新内容。LRU Cache 的替换原则就是将最近最少使用的内容替换掉。

    2024年02月03日
    浏览(32)
  • 【算法】用JAVA代码实现LRU 【缓存】【LRU】

    LRU(Least Recently Used)是一种常见的缓存淘汰策略,用于在缓存空间不足时确定哪些数据应该被淘汰。其基本原则是淘汰最近最少被访问的数据。 工作原理 : 最近使用优先 : LRU算法基于这样的思想:最近被使用的数据很可能在短时间内还会被使用,因此保留这些数据有助于

    2024年01月23日
    浏览(33)
  • 面试遇到算法题:实现LRU缓存

    请你设计并实现一个满足 LRU (最近最少使用) 缓存约束的数据结构。 这是一道大厂面试高频出现的算法题,难度为⭐️⭐️⭐️,属于中等,老铁们来一起看看这个题该怎么解? 没有废话,翠花,上酸菜! 为了实现一个满足 LRU (最近最少使用)缓存约束的数据结构,我们需

    2024年04月25日
    浏览(28)
  • LinkedHashMap如何实现LRU缓存淘汰策略?

    LRU,Least Recently Used, 最近最少使用 ,也就是优先淘汰最近最少使用的元素。 简而言之,就是将LinedHashMap的accessOrder设为true即可。 demo实现如下: 测试一下: 3.1 LinkedHashMap简介 LinkedHashMap内部维护了一个双向链表,能保证元素按插入的顺序访问,也能以访问顺序访问,可以用

    2023年04月24日
    浏览(29)
  • 数据结构与算法之LRU: 实现 LRU 缓存算法功能 (Javascript版)

    关于LRU缓存 LRU - Lease Recently Used 最近使用 如果内存优先,只缓存最近使用的,删除 ‘沉睡’ 数据 核心 api: get set 分析 使用哈希表来实现, O(1) 必须是有序的,常用放在前面,沉睡放在后面, 即:有序,可排序 这样 {} 不符合要求;Map是可以排序的,按照设置顺序 不用 Map 如何

    2024年02月06日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包