java代码实现LRU淘汰策略

LRU: Least Recently Used,最近最少使用的淘汰策略;

在redis中最常使用作为数据淘汰策略;

1. 代码实现

package com.test.wei.biz.lru;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * 使用双向链表实现LRU过期数据淘汰策略
 *
 * @author zhangshiwei
 * @since 2020年11月27日 下午5:29:18
 */
public class LruTest {

    public static void main(String[] args) {
        LruCache lruCache = new LruCache(5);
        lruCache.set("A", "1");
        lruCache.set("B", "2");
        lruCache.set("C", "3");
        lruCache.set("D", "4");
        List<Object> allList = new ArrayList<>();
        allList = lruCache.getAll(lruCache.head, allList);
        System.out.println("新增后 - allList: " + allList);

        lruCache.set("E", "5");
        allList = new ArrayList<>();
        allList = lruCache.getAll(lruCache.head, allList);
        System.out.println("新增后 - allList: " + allList);

        lruCache.set("F", "6");
        allList = new ArrayList<>();
        allList = lruCache.getAll(lruCache.head, allList);
        System.out.println("新增后 - allList: " + allList);

        lruCache.set("G", "7");
        allList = new ArrayList<>();
        allList = lruCache.getAll(lruCache.head, allList);
        System.out.println("新增后 - allList: " + allList);

        LruNode fNode = lruCache.get("F");
        System.out.println("从lruCache中读取: " + fNode.key + " - " + fNode.value);
        allList = new ArrayList<>();
        allList = lruCache.getAll(lruCache.head, allList);
        System.out.println("读取后 - allList: " + allList);
    }

    public static class LruNode {
        String  key;
        Object  value;
        LruNode pre;
        LruNode next;

        public LruNode(String key, Object value) {
            this.key = key;
            this.value = value;
        }
    }

    public static class LruCache {
        // 用KV形式存储对象(内部对象维护双向链表), 链表容量, 头结点, 尾节点
        private HashMap<String, LruNode> map;
        private int                      capacity;
        private LruNode                  head;
        private LruNode                  tail;

        public LruCache(int capacity) {
            this.capacity = capacity;
            this.map = new HashMap<>(capacity);
        }

        public void set(String key, Object value) {
            System.out.println("新增节点的value:" + value);

            LruNode node = map.get(key);
            if (node != null) {
                node.value = value;
                remove(node, false);
            } else {
                node = new LruNode(key, value);

                if (map.size() >= capacity) {
                    System.out.println("空间不足,删除尾节点: " + tail.value);
                    remove(tail, true);
                }
                map.put(key, node);
            }

            // 新增的元素放在队首
            setHead(node);
        }

        // 移除节点
        private void remove(LruNode node, boolean flag) {
            if (null != node.pre) {
                node.pre.next = node.next;
            } else {
                head = node.next;
            }
            if (null != node.next) {
                node.next.pre = node.pre;
            } else {
                tail = node.pre;
            }

            node.pre = null;
            node.next = null;

            if (flag) {
                map.remove(node.key);
            }
        }

        // 设置头节点
        private void setHead(LruNode node) {
            if (null != head) {
                node.next = head;
                head.pre = node;
            }
            head = node;
            if (null == tail) {
                tail = node;
            }
        }

        // 根据key获取节点值,并将此节点移动到队首
        public LruNode get(String key) {
            LruNode node = map.get(key);
            if (null != node) {
                remove(node, false);
                setHead(node);
                return node;
            }
            return null;
        }

        // 获取所有元素的value值
        public List<Object> getAll(LruNode node, List<Object> allList) {
            if (null != node) {
                allList.add(node.value);
                if (null != node.next) {
                    this.getAll(node.next, allList);
                }
            }
            return allList;
        }

    }

}

2. 测试结果

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 可以使用java中的LinkedHashMap类来实现LRU缓存淘汰策略。LinkedHashMap是一种特殊的HashMap,它不仅保存了键值对,还维护了一个双向链表来记录插入顺序,当缓存满后,它会将最先插入的元素淘汰掉。 ### 回答2: LRU(最近最少使用)缓存淘汰策略是指在缓存满时,优先淘汰最近最少使用的数据。实现LRU缓存淘汰策略可以使用链表和哈希表的组合。 首先,我们可以创建一个双向链表的节点类,包含键值对的信息,以及前后指针。链表的头部表示最近访问的节点,尾部表示最久未使用的节点。 我们还需要一个哈希表,用于快速查找节点。哈希表的键是缓存的键,值是对应的节点。 接下来,我们需要实现缓存淘汰策略的几个操作: 1. 获取操作:当尝试获取缓存中的键值对时,如果哈希表中存在该键,则将对应的节点移动到链表头部,并返回该值。如果哈希表中不存在该键,则返回空。 2. 添加操作:当添加新的键值对时,如果该键已存在于缓存中,则将该节点移到链表头部,更新值。否则,创建新节点,并将其插入到链表头部和哈希表中。如果缓存已满,删除链表尾部的节点,并在哈希表中删除对应的键。 3. 删除操作:当从缓存中删除某个键值对时,找到对应的节点,从链表中删除该节点,并在哈希表中删除该键。 以上就是使用Java链表实现LRU缓存淘汰策略的基本思路。通过使用双向链表和哈希表的组合,能够快速实现缓存的增删改查操作,并保持对节点访问的顺序,以便实现LRU策略。 ### 回答3: LRU(Least Recently Used,最近最少使用)是一种常用的缓存淘汰策略,当缓存满时,会将最长时间未被使用的数据从缓存中淘汰。实现LRU缓存淘汰策略可以使用Java中的链表来实现Java中已经提供了LinkedList类,可以直接用于实现链表数据结构。接下来是一个简单的实现LRU缓存的示例代码: ``` import java.util.LinkedList; public class LRUCache<K, V> { private int capacity; private LinkedList<Entry<K, V>> cache; public LRUCache(int capacity) { this.capacity = capacity; this.cache = new LinkedList<>(); } public V get(K key) { Entry<K, V> entry = findEntryByKey(key); if (entry != null) { // 将使用的数据移动到链表头部 cache.remove(entry); cache.addFirst(entry); return entry.value; } return null; } public void put(K key, V value) { Entry<K, V> entry = findEntryByKey(key); if (entry != null) { // 如果key已存在,更新其value,并将数据移动到链表头部 entry.value = value; cache.remove(entry); cache.addFirst(entry); } else { // 如果key不存在,先判断容量是否已满,如果已满则移除最久未使用的数据 if (cache.size() >= capacity) { cache.removeLast(); } // 将新数据插入到链表头部 Entry<K, V> newEntry = new Entry<>(key, value); cache.addFirst(newEntry); } } private Entry<K, V> findEntryByKey(K key) { for (Entry<K, V> entry : cache) { if (entry.key.equals(key)) { return entry; } } return null; } private static class Entry<K, V> { private K key; private V value; public Entry(K key, V value) { this.key = key; this.value = value; } } } ``` 使用示例: ``` LRUCache<String, Integer> cache = new LRUCache<>(3); cache.put("a", 1); cache.put("b", 2); cache.put("c", 3); System.out.println(cache.get("a")); // 输出1 cache.put("d", 4); System.out.println(cache.get("b")); // 输出null,因为b是最久未使用的数据,已被淘汰 ``` 在LRUCache类中,使用LinkedList作为缓存的数据存储结构。缓存的最近使用的数据总是位于链表的头部,当需要访问或更新数据时,将其移动到链表头部。当缓存已满时,移除链表尾部的最久未使用的数据。 这种实现方式可以在O(1)的时间复杂度内实现get和put操作,符合LRU缓存淘汰策略的特性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值