数据结构与算法:LRU缓存机制的算法实现

LRU的算法实现


题目连接.

运用所掌握的数据结构,设计和实现一个==LRU(最近最少使用)==缓存机制,支持一下操作:
1.获取数据get:如果key在缓存中,则获取秘钥的值,否则返回-1;
2.写入数据put:如果秘钥不存在,则写入数据值,当到达上限时,应该删除最近最少使用的值,为新的数据流出空间。
3.LRU的容量为2.

LRU缓存机制

LRU(The Least Recently Used,最近最久未使用算法)是一种常见的缓存算法,在很多分布式缓存系统(Redis,Memcached) 中都有广泛引用。
算法思想
如果一个数据在最近一段时间没有被访问到,那么可以认为在未来被访问到的可能性也很小,因此,当空间满的时候,最久没有访问的数据最先被置换。
在这里插入图片描述

实现:最朴素的思想就是数组+时间戳的方式,不过效率低下,我们可以使用双向链表+哈希表实现。
在这里插入图片描述

解法

解题思路
知识点:哈希表、双向链表,LRU缓存机制。
1.初始化双向链表时设置虚拟头结点和虚拟为结点:
在这里插入图片描述

  • put(1, 1):由于链表容量为0,直接放入即可:
    在这里插入图片描述
  • put(2, 2)
    此时链表容量为1,可以新增节点,且无需删除节点
    在这里插入图片描述
  • get(1)
    此时我们将(1, 1)节点从链表尾部删除,并将其新增至链表头部:
    在这里插入图片描述
  • put(3, 3):此时容量是2,如果新增节点,那么就先删除节点,因此先删除(2, 2),再新增(3,3)节点:
    在这里插入图片描述
    整个操作过程,由于使用了hash表来定位节点位置,put和get的操作时间复杂度为O(1),空间复杂度为O(n)
class LRUCache{
    //定义节点
    private class Node{
        private int key;
        private int value;
        private Node pre;
        private Node next;
        public Node() {}
        public Node(int key, int value){
            this.key = key;
            this.value = value;
        }
    }
    //虚拟头结点和虚拟尾节点
    private Node dummyHead = new Node();
    private Node dummyTail = new Node();
    //LRUCache的容量和当前节点的数量
    private int capacity;
    private int size;

    //HashMap用来查询,存入双向链表的同时,放一份在HashMap
    private HashMap<Integer, Node> hashMap = new HashMap<>();

    //添加至头结点
    private void add(Node node){
        Node originHead = dummyHead.next;
        //即在originHead 和 dummyHead中间插入node
        //双向链表
        dummyHead.next = node;
        node.pre = dummyHead;

        node.next = originHead;
        originHead.pre = node;
    }
    //删除某节点
    private void del(Node node){
        Node preNode = node.pre;
        Node nextNode = node.next;
        preNode.next = nextNode;
        nextNode.pre = preNode;
        node.pre = null;
        node.next = null;
    }
    //初始化一个LRU
    public LRUCache(int capacity){
        dummyHead.next = dummyTail;
        dummyTail.pre = dummyHead;
        this.capacity = capacity;
        size = 0;
    }

    public int get(int key){
        //通过hashmap可以get到元素
        Node node = hashMap.get(key);
        //如果链表中没有,则返回-1
        if(null == node) return -1;
        //在原地删除这个节点,并将整个节点移动到头部
        del(node);
        add(node);
        return node.value;
    }

    public void put(int key, int value){
        Node node = hashMap.get(key);
        //如果链表中存在该节点,则更新该节点并放到头结点
        if(null != node){
            //更新节点的值
            node.value = value;
            del(node);
            add(node);
        }else{
            //如果链表中不存在该元素
            //1.如果此时链表还没装满
            if (size <= capacity) {
                size++;
            }else{
                Node delNode = dummyTail.pre;
                hashMap.remove(delNode.key);
                del(delNode);
            }
            Node newNode = new Node(key, value);
            add(newNode);
            hashMap.put(key,newNode);
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值