Java LRU的两种实现

8 篇文章 0 订阅
4 篇文章 0 订阅

LRU 最近最久未使用,是一种常用的淘汰算法,广泛应用与OS内存页面调度,Redis缓存淘汰策略,等等。在Java中有两种实现方式,一个是直接利用JDK已有的 LInkedHashMap ,一个是自己手写 DoubleLinkedList 结合HashMap。

一:利用JDK方法

public class LRU<K,V> extends LinkedHashMap<K,V>{
    // 容量
    private Integer maxEntries;
    
    // 超过容量则删除最久未使用的,注意是覆盖父类的方法
    @Override
    protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
        return size() > maxEntries;
    }
       
    // 这里的accessOrder要设置成true
    public LRU(int initialCapacity, float loadFactor, boolean accessOrder, Integer maxEntries) {
        super(initialCapacity, loadFactor, true);
        this.maxEntries = maxEntries;
    }
 }

二:自己实现上面的数据结构

心里很清楚是HashMap中的节点又用指针串成双端链表,但是面试的时候在半小时内正确地写出来,还是有很大挑战的。有泛型,静态内部类,链表删除与替换,考察点还挺多的

public class MyLRU<K,V> {
    private Map<K,Node<K,V>> map = new HashMap<>();
    private MyLinkedList<K,V> list = new MyLinkedList<>();
    // 和上面的容量一个意思
    private int capacity;

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

	//往LRU中添加数据,主要用map的put方法
    public void add(K key, V value){
        if(map.containsKey(key)){
            Node<K,V> node = map.get(key);
            node.value = value;
            map.put(key,node);
            list.moveToTail(node);
        }else{
            if(map.size() == capacity){
                K k = list.removeHead();
                map.remove(k);
            }
            Node<K,V> node = new Node<>(key, value);
            map.put(key,node);
            list.add(node);
        }
    }

	// 从LRU中获取数据,要把数据提取到最近使用
    public V get(K key){
        if(map.containsKey(key)){
            Node<K,V> node = map.get(key);
            list.moveToTail(node);
            return  node.value;
        }
        return null;
    }

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

        Node(K key, V value) {
            this.key = key;
            this.value = value;
        }
    }

    private static class MyLinkedList<K,V> {
        // head 是老数据
        Node<K,V> head;
        Node<K,V> tail;

        // 添加新数据到tail
        private void add(Node<K,V> node) {
            if (node == null) {
                throw new NullPointerException("node 为 空");
            }
            if (head == null) {
                head = node;
                tail = node;
            } else {
                tail.next = node;
                node.prev = tail;
                tail = node;
            }
        }

        // 移动数据到tail
        private void moveToTail(Node<K,V> node) {
            if (node == null) {
                throw new NullPointerException("node 为 空");
            }
            // 已经末尾了
            if (node.next == null) {
                return;
            }
            if (node.prev == null) {
                head = head.next;
            }
            node.next.prev = node.prev;
            if (node.prev != null) {
                node.prev.next = node.next;
            }
            tail.next = node;
            node.prev = tail;
            node.next = null;
            tail = node;
        }

        // 删除最老的数据
        private K removeHead() {
            if(head == null) {
                return null;
            }
            K key = head.key;
            if(head == tail){
                head = null;
                tail = null;
            }else{
                head = head.next;
                head.prev = null;
            }
            return key;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            Node cur = head;
            while(cur != null){
                sb.append(cur.key).append(" ");
                cur = cur.next;
            }
            sb.append("\n头是 ").append(head.key).append(" 尾是 ").append(tail.key);
            return sb.toString();
        }
    }



    public static void main(String[] args) {
        MyLRU<String,Integer> myLRU = new MyLRU<>(3);
        myLRU.add("A", 1);
        myLRU.add("B", 2);
        myLRU.add("C", 3);
        System.out.println(myLRU.get("A"));
        myLRU.add("D", 4);
        System.out.println(myLRU.get("B"));
        System.out.println(myLRU.list);
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值