Map+双向链表实现LRU算法

93 篇文章 0 订阅
  • map+双向链表实现,其中双向链表头结点的后继节点依次存储最近使用的缓存数据,尾节点的前驱节点为最久未被使用的数据;当通过key查询缓存在map中,则将对应节点移动至头结点的后面;key不在缓存中时,新建一个节点,并移动至头结点后面。

  • 实现代码如下所示:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Map+双向链表实现LRU
 *
 * @param <V>
 */
public class LRU<V> {
    // 缓存的数量
    private int capacity = 1024;

    // 缓存对应的map
    private Map<String, Node<String, V>> table = new ConcurrentHashMap<>();

    // 双向链表头结点
    private Node<String, V> head;

    // 双向链表尾节点
    private Node<String, V> tail;


    public LRU(int capacity) {
        this();
        this.capacity = capacity;
    }

    public LRU() {
        head = new Node<>();
        tail = new Node<>();
        head.next = tail;
        head.pre = null;
        tail.pre = head;
        tail.next = null;
    }

    /**
     * 获取缓存
     *
     * @param key
     * @return
     */
    public V get(String key) {
        // 如果key不在table里面,说明缓存里面没有
        Node<String, V> currNode = table.get(key);
        if (currNode == null) {
            return null;
        }

        // 如果key存在table里面,则将key对应的node放到对头
        currNode.pre.next = currNode.next;
        currNode.next.pre = currNode.pre;

        moveNode2Head(currNode);

        return currNode.value;
    }

    /**
     * 将当前节点移动到链表尾部
     *
     * @param currNode
     */
    private void moveNode2Head(Node<String, V> currNode) {
        // 当前节点存在链表中要找到当前节点的位置,并把其删除
        // HEAD->A
        currNode.next = head.next;
        head.next.pre = currNode;
        currNode.pre = head;
        head.next = currNode;
    }


    /**
     * 保存缓存
     *
     * @param key
     * @param v
     */
    public void put(String key, V v) {
        // 如果存在缓存里面,更新当前node的位置
        Node<String, V> currNode = table.get(key);
        if (currNode == null) {
            // 如果不存在的话,判断是否超过空间大小,如果超过空间大小,将尾部的节点删除掉;如果没有超过空间大小,插入到table里面
            if (table.size() == capacity) {
                // 删除当前节点
                table.remove(tail.pre.key);

                tail.pre.pre.next = tail;
                tail.pre = tail.pre.pre;
            }

            currNode = new Node();
            currNode.key = key;
            currNode.value = v;
            table.put(key, currNode);
        } else {
            currNode.pre.next = currNode.next;
            currNode.next.pre = currNode.pre;
        }

        moveNode2Head(currNode);
    }

    static class Node<K, V> {
        private K key;
        private V value;
        private Node<K, V> pre;
        private Node<K, V> next;

    }


    public static void main(String[] args) {
        LRU<Integer> lru = new LRU(20);

        for (int i = 0; i < 100; i++) {
            lru.put("a", 1);
            lru.put("b", 2);
            lru.put("c", 3);

            Integer a1 = lru.get("a");

            lru.put("c", 3);
            lru.put("d", 4);
            lru.put("e", 5);
            Integer a = lru.get("a");

            lru.put("e", 6);
            lru.put("f", 7);

            lru.put("i" + i / 10, i);
        }
        System.out.println(lru);

        while (lru.head != null) {
            System.out.println(lru.head.key + "-" + lru.head.value);
            lru.head = lru.head.next;
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用 Java 实现 LRU 算法的基本步骤是:1. 定义一个双向链表;2. 重写put()和get()方法;3. 在put()方法中,如果元素已存在,移动到链表头部;4. 在get()方法中,如果元素存在,移动到链表头部;5. 如果缓存已满,移除链表尾部的元素。 ### 回答2: 使用Java实现lru算法可以通过使用LinkedHashMap实现。 LinkedHashMap是HashMap的子类,它通过维护一个双向链表来记录插入顺序。我们可以利用LinkedHashMap的特性来实现lru算法。 具体实现步骤如下: 1. 创建一个继承自LinkedHashMap的子类LRUMap,指定其泛型为<K, V>。 2. 重写LRUMap的构造方法,传入一个capacity参数来指定LRUMap的容量,并调用父类LinkedHashMap的构造方法来初始化LRUMap。 3. 在重写的构造方法中,使用super(capacity, 0.75f, true)来调用父类构造方法,并将最后一个参数设置为true,表示开启访问顺序模式。 4. 重写LRUMap的removeEldestEntry方法,当LRUMap的大小超过指定容量时,移除最老的键值对。 5. 至此,我们已经完成了LRUMap实现。 下面是一个使用LRUMap的示例: ```java import java.util.LinkedHashMap; public class LRUMap<K, V> extends LinkedHashMap<K, V> { private final int capacity; public LRUMap(int capacity) { super(capacity, 0.75f, true); this.capacity = capacity; } @Override protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return size() > capacity; } public static void main(String[] args) { LRUMap<String, Integer> lruMap = new LRUMap<>(3); lruMap.put("a", 1); lruMap.put("b", 2); lruMap.put("c", 3); lruMap.put("d", 4); System.out.println(lruMap); // 输出: {b=2, c=3, d=4} } } ``` 以上示例中,我们创建了一个容量为3的LRUMap,并进行了插入操作。当容量超过3时,最老的键值对"a"会被移除,而最新的键值对"d"则会按照访问顺序保存在LRUMap中。最后,我们打印出LRUMap的内容,验证了LRU算法实现。 ### 回答3: LRU(Least Recently Used,最近最少使用)是一种常见的缓存淘汰算法,其中使用Java实现LRU算法的原理是根据数据的使用情况对缓存中的数据进行淘汰,将最近最少使用的数据移除,以腾出空间存储新的数据。 在Java中,我们可以使用LinkedHashMap实现LRU算法。LinkedHashMap是HashMap的子类,它可以保持插入顺序或访问顺序。 下面是一个简单的使用Java实现LRU算法的示例代码: ```java import java.util.LinkedHashMap; import java.util.Map; public class LRUCache<K, V> extends LinkedHashMap<K, V> { private int capacity; // 缓存容量 public LRUCache(int capacity) { super(capacity, 0.75f, true); // 设置访问顺序为true,保持LRU特性 this.capacity = capacity; } @Override protected 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.put(4, "D"); System.out.println(cache); // 输出:{2=B, 3=C, 4=D} cache.get(2); System.out.println(cache); // 输出:{3=C, 4=D, 2=B} } } ``` 在以上示例代码中,我们继承了LinkedHashMap,并重写了`removeEldestEntry`方法,当缓存大小超过容量时,会自动移除最久未使用的数据。 通过以上代码,我们可以使用Java实现LRU算法,并对缓存中的数据进行淘汰。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值