LRU缓存简单实现

第一次看到这个题目,我懵逼了,啥是LRU,因而乎我去百度了一下,大概的意思是这样的,LRU是Least Recently Used的缩写,即最近最少使用,选择最近最久未使用的key予以淘汰。 大概了解后我想到(实际想了半天。。。而且还参考了网上的其余人的一些思路)node

既然要频繁的删除和插入,那确定首选链表,大概思路分以下几步: 1.须要一个双向链表,头节点和尾节点 2.HashMap存储key, HashMap的Value为双向链表LRU的Node节点 3.put插入时判断该key是否存在,若是不存在,再判断是否空间满了,满了就删除末尾节点(最少使用节点),而后把新插入元素放到头节点,若是没满则插入到链表头节点,若是已存在,则移动该节点到头节点 4.get获取节点时有则返回,而且把该节点移动到链表的头节点bash

代码实现以下:测试

/**
 * 双向链表
 */
class LinkNode {

    /**
     * 前节点
     */
    LinkNode pre;
    /**
     * 后节点
     */
    LinkNode next;
    int key;
    int val;
}

public class LRUCache {
    private int capacity;
    private LinkNode head;
    private LinkNode tail;
    private HashMap<Integer,LinkNode> cache;

    public LRUCache(int capacity) {
        this.capacity=capacity;
        cache = new HashMap<>(capacity);
    }

    public int get(int key) {
        LinkNode res = cache.get(key);
        if(res == null){
            return -1;
        }
        moveNodeToFirst(res);
        return res.val;
    }

    public void put(int key, int value) {
        LinkNode tempLinkNode = cache.get(key);
        if(tempLinkNode == null){
            if(cache.size() >= capacity){
                removeLastNode();
            }
            tempLinkNode = new LinkNode();
            tempLinkNode.key = key;
        }
        tempLinkNode.val = value;
        moveNodeToFirst(tempLinkNode);
        cache.put(key, tempLinkNode);
    }

    /**
     * put或者get时移动该节点到链表的头节点
     * @param node
     */
    private void moveNodeToFirst(LinkNode node) {
        //空链表时放入第一个元素
        if(head == null){
            tail = head = node;
            return;
        }
        //链表的头部
        if (head == node) {
            return;
        }
        //链表的尾部
        else if(tail == node){
            //把他前面的节点变成尾节点(他要被移动到链表开头了)
            tail = tail.pre;
        }
        //在链表中间的节点
        else if(node.next != null || node.pre != null){
            //节点被移动到头部后,相邻节点的先后节点值变化
            assert node.pre != null;
            node.pre.next = node.next;
            assert node.next != null;
            node.next.pre = node.pre;
        }

        //原来的链表头部,变成第二个
        node.next = head;
        //节点被移动到头部后,相邻节点的先后节点值变化
        head.pre = node;
        //放到头部后他的前节点为空
        node.pre = null;
        //放到链表头部
        head = node;
    }

    /**
     * 超过hashMap容量时删除最后一个元素,即最少使用元素
     */
    private void removeLastNode() {
        LinkNode tempLinkNode = tail;
        //倒数第二个节点变成最后一个节点
        tail = tail.pre;
        if(tail != null){
            tail.next = null;
        }else{
            head = null;
        }
        cache.remove(tempLinkNode.key);
    }
}

复制代码

测试ui

public static void main(String[] args) {
        LRUCache cache = new LRUCache( 2 );
        cache.put(1, 1);
        cache.put(2, 2);
        System.out.println("获取1的值" + cache.get(1));
        cache.put(3, 3);
        System.out.println("key:3已插入, key:2,被删除");
        System.out.println("获取2的值" + cache.get(2));
        cache.put(4, 4);
        System.out.println("key:4已插入, key:1,被删除");
        System.out.println("获取1的值" + cache.get(1));
        System.out.println("获取3的值" + cache.get(3));
        System.out.println("获取4的值" + cache.get(4));
    }
复制代码

结果this

获取1的值:1
key:3已插入, key:2,被删除
获取2的值:-1
key:4已插入, key:1,被删除
获取1的值-1
获取3的值:3
获取4的值:4
复制代码

参考资料:cloud.tencent.com/developer/a… www.jianshu.com/p/34c03210c…spa

相关文章
相关标签/搜索