LRU 缓存实现

1.什么是LRU缓存?

       LRU缓存是一个指定大小容量的缓存,随着元素不断的增加,如果达到容量的上线,会优先删除最近最少使用的数据。同时每次put/get操作都会调整数据位置为最新的缓存,每次put/get操作的时间复杂度是O(1)

2.LRU的应用场景有哪些?

       mysql的buffer pool 缓存策略是LRU的优化版,redis 内存不足的缓存淘汰策略有LRU等

3.LRU的实现方式有哪些?


     一种使用自实现双向链表+hashmap,第二种是指定大小容量的linkedhashmap,内部结构如图所示


put(k,v) 实现逻辑
分三种情况
     1.检测map中是否存在,如果存在,先从链表删除,新节点添加到链表末尾,添加到hashmap中
     2.map中不存在,map没有达到最大容量,添加到链表末尾,添加到hashmap中
     3.map中存在.先从链表中删除头结点(头结点存放最近最少使用的节点),hashmap中移除头结点,新节点添加到链表
put(k,v) 实现逻辑
分两种情况
     1.检测hashmap中是否存在,如果存在,先从链表中删除,新节点添加链表尾部,并返回value值
     2.如果hashmap中不存在.直接返回-1

LRU缓存策略实现

第一种基于自实现的双向链表+hashmap的实现如下

package com.mashibing.my;

import java.util.HashMap;
import java.util.Map;

//自实现双向链表+hashmap=lru(最近最少使用缓存)
//put(k,v) 
//分三种情况
//1.检测map中是否存在,如果存在,先从链表删除,新节点添加到链表末尾,添加到hashmap中
//2.map中不存在,map没有达到最大容量,添加到链表末尾,添加到hashmap中
//3.map中存在.先从链表中删除头结点(头结点存放最近最少使用的节点),hashmap中移除头结点,新节点添加到链表中,添加到map中
//get(k,v)
//1.检测hashmap中是否存在,如果存在,先从链表中删除,新节点添加链表尾部,并返回value值
//2.如果hashmap中不存在.直接返回-1
public class LRUCache2 {

    class Node {
        Node pre;
        Node next;
        Integer key;
        Integer val;

        public Node() {
        }

        Node(Integer k, Integer v) {
            key = k;
            val = v;
        }
    }

    Map<Integer, Node> map = new HashMap<Integer, Node>();
    //双向链表的头结点和尾结点
    Node head, tail;
    //最大容量
    int cap;

    public LRUCache2(int capacity) {
        this.cap = capacity;
        this.head = new Node();
        this.tail = new Node();
        head.next = tail;
        tail.pre = head;
    }

    public int get(int key) {
        Node n = map.get(key);
        if (n != null) {
            //删除n节点
            deleteNode(n);
            appendTail(n);
            return n.val;
        }
        return -1;
    }

    public void put(int key, int value) {
        Node n = map.get(key);
        // existed
        if (n != null) {
            n.val = value;
            map.put(key, n);
            deleteNode(n);
            appendTail(n);
            return;
        }
        // else {
        if (map.size() == cap) {
            //达到链表的长度,从链表的头部删除元素
            //删除头结点
            Node tmp = head.next;
            deleteNode(head.next);
            //map中移除key
            map.remove(tmp.key);
        }
        n = new Node(key, value);
        // youngest node append tail
        //向链表的尾部添加元素
        appendTail(n);
        map.put(key, n);
    }

    private void appendTail(Node n) {
        Node cur = tail.pre;
        n.next = tail;
        n.pre = cur;
        cur.next = n;
        tail.pre = n;
    }

    private void deleteNode(Node n) {
        n.pre.next = n.next;
        n.next.pre = n.pre;
    }

    public static void main(String[] args) {
        LRUCache2 cache = new LRUCache2(2 /* 缓存容量 */);
        cache.put(1, 1);
        cache.put(2, 2);
        System.out.println(cache.get(1));       // 返回  1
        cache.put(3, 3);    // 该操作会使得密钥 2 作废
        System.out.println(cache.get(2));       // 返回 -1 (未找到)
        cache.put(4, 4);    // 该操作会使得密钥 1 作废
        System.out.println(cache.get(1));      // 返回 -1 (未找到)
        System.out.println(cache.get(3));       // 返回  3
        System.out.println(cache.get(4));      // 返回  4
    }
}

第二种实现方式 指定大小容量的linkedhashmap
 

import java.util.LinkedHashMap;
import java.util.Map;


public class LRUcache3 {
    private int capacity;
    private LinkedHashMap<Integer, Integer> cache;
    public LRUcache3(int capacity) {
        this.capacity = capacity;
        this.cache = new java.util.LinkedHashMap<Integer, Integer> (capacity, 0.75f, true) {
            // 定义put后的移除规则,大于容量就删除eldest
            @Override
            protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
                return size() > capacity;
            }
        };
    }
    public int get(int key) {
        Integer value = cache.get(key);
        if(value==null){
            return -1;
        }
        cache.remove(key);
        cache.put(key,value);
        return value;
    }
    public void put(int key, int value) {
        if (cache.containsKey(key)) {
            cache.remove(key);
        }
        cache.put(key, value);
    }

    public static void main(String[] args) {
        LRUcache3 cache = new LRUcache3(2 /* 缓存容量 */);
        cache.put(1, 1);
        cache.put(2, 2);
        System.out.println(cache.get(1));       // 返回  1
        cache.put(3, 3);    // 该操作会使得密钥 2 作废
        System.out.println(cache.get(2));       // 返回 -1 (未找到)
        cache.put(4, 4);    // 该操作会使得密钥 1 作废
        System.out.println(cache.get(1));      // 返回 -1 (未找到)
        System.out.println(cache.get(3));       // 返回  3
        System.out.println(cache.get(4));      // 返回  4
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值