Java实现LRU算法

本文介绍了LRU(最近最少使用)算法及其在计算机操作系统中的应用。详细讲解了在Java中实现LRU缓存的两种方法:一是利用HashMap结合双向链表,二是直接使用内置的LinkedHashMap。通过示例代码展示了具体实现过程,并验证了正确性。

LRU算法

LRU(Least recently used)—最近最少被使用算法。在一些内存算法表现中若在一个内存有限的环境中,出现内存不足时为了保证程序的正常运行,会将一些价值较低的对象(如何来评定一个对象的价值的高低,对于LRU算法来说:如果数据最近被访问过,那么将来被访问的几率也更高,那么对应的价值就越高)进行清除,空出内存空间。

计算机操作系统基础理论中有一个经典理论:最近使用的页面数据会在未来一段时期内仍然被使用,已经很久没有使用的页面很有可能在未来较长的一段时间内仍然不会被使用。

2:LRU算法应用实现

在缓存应用中,使用LRU算法可以保证缓存数据量的可控,一旦缓存数据总量超过指定阀值,就将最近最少被访问的数据给清除掉。下面的具体的实现都基于cache需求来实现

2.1:Java中cache的实现(HashMap+双向链表实现)

实现思路:使用HashMap中value存储双向链表的各个节点,双向链表按照数据写入顺序的数据存储,一旦任意数据被访问,获取HashMap中该数据所在节点,将此节点移动到head(表示该数据最近被访问到),重新连接该节点上下节点。最终经常访问的数据会在双向链表前端聚齐,而不经常被访问的数据会聚集在链表尾部,一旦出现数据总量超过阀值时,我们可以通过将尾部的数据直接移除,来保证整个缓存的健康。

这里为何选用HashMap+双向链表来实现:

  1. HashMap的k,v结构对应这cache中k,v的概念,所以使用HashMap中V存储双向链表中的Node
  2. HashMap中查询写入的时间复杂度为O(1)
  3. 双向链表中的节点的移动,删除的时间复杂度为O(1)。
  4. 双向链表可以使我们通过任意一个节点获取其它所有节点

源码:

/**
 * 基于HashMap+双向链表
 * @author fangyuan
 */
public class MyLRUCache<K,V> {

    /**
     * 用于存储所有节点数据【利用HashMap中读写为O(1)特性】可以快速获取节点
     */
    private HashMap<K,Node<K,V>> nodes;

    /**
     * 用于存储双向链表头
     */
    private Node<K, V> head;

    /**
     * 用于存储双向链尾
     */
    private Node<K, V> tail;

    /**
     * 缓存中最大数据深度
     */
    private Integer maxSize;


    public MyLRUCache(Integer maxSize){

        if( ( maxSize =(maxSize ==null ? 16:maxSize))<6){

            throw new RuntimeExcept
LRU算法(最近最少使用)是一种常见的缓存淘汰算法,它根据数据最近被访问的时间来选择淘汰哪些数据。下面是一个简单的Java实现LRU算法的例子: ```java import java.util.LinkedHashMap; import java.util.Map; public class LRUCache<K, V> extends LinkedHashMap<K, V> { private final int MAX_CACHE_SIZE; public LRUCache(int cacheSize) { super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true); MAX_CACHE_SIZE = cacheSize; } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_CACHE_SIZE; } public static void main(String[] args) { LRUCache<String, Integer> cache = new LRUCache<>(3); cache.put("key1", 1); cache.put("key2", 2); cache.put("key3", 3); System.out.println(cache.keySet()); cache.put("key4", 4); System.out.println(cache.keySet()); cache.put("key3", 3); System.out.println(cache.keySet()); cache.put("key5", 5); System.out.println(cache.keySet()); } } ``` 在这个例子中,我们使用了Java的LinkedHashMap类,它可以按照插入顺序或访问顺序进行遍历。我们继承这个类,并重写了removeEldestEntry方法,当缓存的大小超过最大值时,自动删除最近最少使用的数据。我们还可以使用put方法向缓存中添加数据,使用get方法从缓存中获取数据。 在main方法中,我们创建了一个缓存大小为3的LRUCache对象,并向其中添加了4个键值对。在第一次打印缓存的键集合时,输出结果为[key1, key2, key3]。当添加第4个键值对时,由于缓存大小已经到达了最大值,所以自动删除最近最少使用的key1,输出结果为[key2, key3, key4]。当再次使用key3时,它将变成最新的,输出结果为[key2, key4, key3]。当添加第5个键值对时,由于缓存大小已经到达了最大值,所以自动删除最近最少使用的key2,输出结果为[key4, key3, key5]。 这个例子中使用了泛型,可以存储任何类型的数据。如果要存储其他类型的数据,只需要将K和V的类型改为相应的类型即可。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值