Java实现LRU缓存

Java实现LRU缓存

问题描述:LRU是Least Recently Used 的缩写,翻译过来就是“最近最少使用”,LRU缓存就是使用这种原理实现,简单的说就是缓存一定量的数据,当超过设定的阈值时就把一些过期的数据删除掉,比如我们缓存10条数据,当数据小于10时可以随意添加,当超过10时就需要把新的数据添加进来,同时要把过期数据删除,以确保我们最大缓存10条,每次将被访问数据放在cache最前端,以保证cache中数据按被访问的先后顺排列。

解决思路
由于有删除、插入和移动操作,因此选择链表实现。为了提高操作效率,采用双向链表,并用head和tail记录链表的头尾节点。
在进行查询的时候,由于链表时间复杂度为O(n),因此使用HashMap辅助降低查询的时间复杂度。
1.查询: 直接从HashMap中获取;
2.删除: 先从HashMap中删除,再删除其尾节点;
3.插入: 先放入HashMap,在插入为头结点;
4.移动: 将指定节点移动为头结点

代码及注释如下

import java.util.HashMap;
public class MyLRU {
    //记录cache中已缓存元素个数
    private int length = 0;

    //双向链表的头指针和尾指针
    private DoubleLinkedNode head;
    private DoubleLinkedNode tail;

    //存储元素的map,其中key为DoubleLinkedNode的key,value 为DoubleLinkedNode
    HashMap<Integer, DoubleLinkedNode> nodeMap = new HashMap();

    //根据key值从cache中获取value
    public int get(int key) {
        int value = -1;
        //如果cache中包含该元素,则返回,否则返回 -1
        if (nodeMap.containsKey(key)) {
            //从map中获取节点
            DoubleLinkedNode node = nodeMap.get(key);
            //将节点放到队首。如果head == tail则说明只有一个节点,则无需处理。
            if(head != tail){
                //如果node.pre == null,则说明其为头结点,也不用处理
                if (node.pre != null) {
                    //处理其后续节点
                    if (node.next != null) {
                        //如果有后续节点,则需要将后续节点的前指针指向其前节点
                        node.next.pre = node.pre;
                    }else{
                        //如果node.next==null,则其为尾节点,其移动到头结点,
                        //会对尾节点tail产生影响,因此需要先处理tail
                        tail = tail.pre;
                    }
                    //处理前节点:其后节点的前指针指向其前节点;
                    node.pre.next = node.next;
                    //将其插入到头部
                    node.next = head;
                    head.pre = node;
                    head = node;
                }
            }
            //取值
            value = head.value;
        }
        showAllValues();
        return value;
    }

    //向cache中新增元素
    public void put(int key, int value) {
        DoubleLinkedNode node = new DoubleLinkedNode(key, value);
        nodeMap.put(key, node);
        if(head == null){
            head = node;
            tail = node;
        }else{
            if(length >= 5){
                nodeMap.remove(tail);
                tail = tail.pre;
                tail.next = null;
                length--;
            }
            node.next = head;
            head.pre = node;
            head = node;
        }
        length++;
        showAllValues();
    }
    //按顺序输出cache中现有的元素,可用于测试算法是否正确,无实际意义
    private void showAllValues() {
        DoubleLinkedNode node = head;
        while (node != null) {
            System.out.print(node.key + " ");
            node = node.next;
        }
        System.out.println();
    }
    //节点
    private class DoubleLinkedNode {
        int key;
        int value;
        DoubleLinkedNode pre;
        DoubleLinkedNode next;

        public DoubleLinkedNode(int key, int value) {
            this.key = key;
            this.value = value;
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值