LRU缓存机制

设计一个存储key-value的值,需要能get到对应key的值,在存储的时候如果关键字存在则变更,如果不存在则存储,如果容量满了则删除最久没使用的值,会用到一个哈希表和一个双向链表,用哈希表来存储键值对,用双向链表来存储使用顺序。越靠近头部越是最近使用的,使用也就一位这使用了get()
get时如果哈希表不存在key则返回-1,如果存在则得知在双向链表中的下标,将它移动到头部并返回。
put时如果key不存在则创造一个新的节点。并在双向链表的头部添加该节点(使用意味着添加和返回都算),并将其添加到哈希表中。如果key存在,则先通过哈希表定位找到该节点,然后再改变它的位置到双向链表的头部。
哈希表可以用hashmap,然后双向链表需要自己实现。
双向链表的操作共三步,在双向链表的头部添加节点,在双向链表的尾部删除节点,将指定节点移向头部的操作就是先删除然后再头部添加。
在实现的时候设置一个伪头部和一个伪尾部,这样就不用检查相邻的节点是否存在而可以直接添加或删除。

class LRUCache {
     class Node{//双向链表的节点类
        int key;//此节点的键
        int value;//此节点的值
        Node prev;//前一个节点
        Node next;//后一个节点
        public Node(){}
        public Node(int key,int value){
            this.key=key;
            this.value=value;
        }
    }
    //缓存类的初始化
    private Map<Integer, Node> map = new HashMap<Integer, Node>();//实现这个缓存机制的哈希表,key对应双向链表节点
    private Node head, tail;//双向链表的头结点和尾结点
    private int size;//此时的大小
    private int capacity;//要求的容量
    public LRUCache(int capacity){//缓存类的构造函数
        this.size=0;
        this.capacity=capacity;
        head=new Node();//初始化头结点尾结点
        tail=new Node();
        head.next=tail;
        tail.prev=head;
    }
    // 双向链表的方法,共四个
     private void addToHead(Node node) {
        node.prev = head;
        node.next = head.next;
        head.next.prev = node;
        head.next = node;
    }

    private void removeNode(Node node) {
        node.prev.next = node.next;
        node.next.prev = node.prev;
    }
     private Node removeTail() {
        Node res = tail.prev;
        removeNode(res);
        return res;
    }
    private void moveToHead(Node node) {
        removeNode(node);
        addToHead(node);
    }
    // LRU缓存核心方法get和put
    public int get(int key) {
        if(map.containsKey(key)){
            Node n=map.get(key);
            moveToHead(n);
            return n.value;
        }else{
            return -1;
        }
    }
    
    public void put(int key, int value) {
        if(map.containsKey(key)){
            Node n=map.get(key);
            n.value=value;
            moveToHead(n);
        }else{
            Node n=new Node(key,value);
            map.put(key,n);
            addToHead(n);
            size++;
            if(size>capacity){
                Node tail=removeTail();
                map.remove(tail.key);
                --size;
            }
        }
    }
}

上一篇:Redis 内存耗尽的淘汰策略 LRU与LFU算法


下一篇:mysql分页缓冲池占用很高怎么解决_缓冲池(buffer pool),这次彻底懂了!!!