首页 > 编程语言 >Java实现自定义LRU算法

Java实现自定义LRU算法

时间:2023-04-10 23:36:58浏览次数:33  
标签:Node map Java 自定义 int 链表 LRU key public

class LRUCache {
    // key -> Node<key,val>
    private HashMap<Integer, Node> map;
    // Node(k1,v1) <-> Node(k2,v2)
    private DoubleList cache;
    // 最大容量
    private int cap;

    public LRUCache(int capacity) {
        this.cap = capacity;
        map = new HashMap<>();
        cache = new DoubleList();
    }   
    
    public int get(int key) {
        if(!map.containsKey(key)){
            return -1;
        }
        // 将该数据升为最近使用的
        makeRecently(key);
        return map.get(key).val;
    }
    
    public void put(int key, int value) {
        if(map.containsKey(key)){
            //删除旧数据
            deleteKey(key);
            //新插入的数据未最近使用的数据
            addRecently(key, value);
            return;
        }
        
        if(cap == cache.size()){
            // 删除最久未使用的元素
            removeLeastRecently();
        }
        //添加新元素为最近使用的元素
        addRecently(key, value);
    }

    // 将某个key提升为最近使用的
    private void makeRecently(int key){
        Node x = map.get(key);
        // 先从链表中删除这个节点
        cache.remove(x);
        //重新插到队尾
        cache.addLast(x);
    }

    // 添加最近使用的元素
    private void addRecently(int key, int val){
        Node x = new Node(key, val);
        // 链表尾部就是最近使用的元素
        cache.addLast(x);
        //在map中添加key的映射
        map.put(key, x);
    }

    // 删除某一个key
    private void deleteKey(int key){
        Node x = map.get(key);
        // 从链表中删除
        cache.remove(x);
        // 从map中删除
        map.remove(key);
    }

    // 删除最久未使用的元素
    private void removeLeastRecently(){
        // 链表头部的第一个元素就是最久未使用的
        Node deleteNode = cache.removeFirst();
        // 删除map中的映射
        int deletedKey = deleteNode.key;
        map.remove(deletedKey);
    }
}

// 定义双向链表的节点
// 默认 key和value为int类型
class Node{
    public int key,val;
    public Node next,prev;
    public Node(int k, int v){
        this.key = k;
        this.val = v;
    }
}

// 构建一个双向链表
class DoubleList{
    // 定义头尾虚节点
    private Node head, tail;
    // 链表元素数
    private int size;

    public DoubleList(){
        // 初始化双向链表
        head = new Node(0,0);
        tail = new Node(0,0);
        head.next = tail;
        tail.prev = head;
        size = 0;
    }

    // 在链表尾部添加节点x,时间为O(1)
    public void addLast(Node x){
        x.prev = tail.prev;
        x.next = tail;
        tail.prev.next = x;
        tail.prev = x;
        size++;
    }

    // 删除链表中的x节点(x一定存在)
    // 由于是双链表且给的是目标Node节点,时间为O(1)
    public void remove(Node x){
        x.prev.next = x.next;
        x.next.prev = x.prev;
        size--;
    }

    //删除链表中第一个节点,并返回该节点,时间O(1)
    public Node removeFirst(){
        if(head.next == null){
            return null;
        }
        Node first = head.next;
        remove(first);
        return first;
    }

    // 返回链表的长度,时间O(1)
    public int size(){
        return size;
    }
}

 

标签:Node,map,Java,自定义,int,链表,LRU,key,public
From: https://www.cnblogs.com/zhaozihang/p/17304720.html

相关文章

  • 6.自定义Form表单验证
    在web程序中存在大量的表单数据验证,而我们通过self.get_argument(arg)进行获取用户输入参数验证会存在的重复代码 1.自定义表单app.py文件代码如下:MyForm类对象属性中封装需要验证的字段并与浏览器中验证的字段保持一致,MyForm类中check_valid方法获取用户输入的参数并进行验证......
  • kettle从入门到精通 第十一课 kettle javascript 解析json数组
    1、json步骤虽然可以解析json数组,但是不够灵活。通过javascript步骤来解析json数组比较灵活,且可以按照需要组装数据流转到下个步骤。1)步骤名称:可以自定义2)TransformScripts:当前步骤编写的javascript脚本3)TransformConstants:重新定义的静态常量,用于控制数据行发生的情况。您必......
  • 区块链学习(9)-自定义修饰词modifier
    在Solidity中,修饰词(modifier)是一种代码重用和逻辑抽象的方法,用于修改函数的行为。它可以在函数执行前进行预处理(如检查条件、权限等),或在函数执行后进行后处理。修饰词在智能合约中非常有用,尤其是用于访问控制、状态检查和重入保护等场景。修饰词定义和使用:要定义一个修饰词,需要使用......
  • Java8统计金额demo
    Java8统计金额demopackagecom.example.core.mydemo.java8;publicclassGoodsPriceDTO{privateStringgoodName;privateIntegeramount;publicStringgetGoodName(){returngoodName;}publicvoidsetGoodName(StringgoodName){......
  • Java8 - sum求和,将 List 集合转为 Map,key去重(groupingBy),sorted排序
    Java8-sum求和,将List集合转为Map,key去重(groupingBy),sorted排序packagecom.example.core.mydemo.java8;publicclassGoodsPriceDTO{privateIntegerid;privateStringgoodName;privateIntegeramount;//重写toString方法,System可以打印输出......
  • JAVA基础-StringUtils
    依赖<!--commons--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.10</version></dependency>举例importorg.apache.commons.lang......
  • [golang]使用logrus自定义日志模块
    简介logrus是一个第三方日志库,性能虽不如zap和zerolog,但方便易用灵活。logrus完全兼容标准的log库,还支持文本、JSON两种日志输出格式。特点相较于标准库,logrus有更细致的日志级别,从高到低分别是:trace>debug>info>warn>error>fatal>panic支持自定义日志格式,内置支......
  • Java 基础
    一、基础1.标识符注意点所有的标识符都应该以字母(A-Z或者a-z),美元符($),或者下划线(_)开始首字符之后可以是字母,美元符,下划线或者数字的任何字符组合不能使用关键字作为方法名或者变量名标识符是大小写敏感的合法标识符举例:age、$salary、_value、__1_value非法标识符举例:1......
  • Context响应,重定向,自定义函数,Abort
    前言:Context对象提供了很多内置的响应形式,JSON、HTML、Protobuf、MsgPack、Yaml、String等。它会为每一种形式都单独定制一个渲染器。Context是Gin最重要的部分。它允许我们在中间件之间传递变量,管理流程,验证请求的JSON并呈现JSON响应。正文: content响应字符串,json,及......
  • Java并发(一)----进程、线程、并行、并发
    一、进程与线程进程程序由指令和数据组成,但这些指令要运行,数据要读写,就必须将指令加载至CPU,数据加载至内存。在指令运行过程中还需要用到磁盘、网络等设备。进程就是用来加载指令、管理内存、管理IO的当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进......