LRU自定义最近最少使用-java实现

LRU自定义最近最少使用

一:leetCode 题目

题目链接:

题目链接:146.LRU缓存

为什么要写博客记录下呢?

1.这个题很锻炼自己的编码能力(代码量多,结构多)

2.这个题很锻炼自己的owner能力(感觉挑战底层类,不屈于写业务代码)

3.这个题很锻炼自己的耐力(调试比较麻烦)

4.这个题很锻炼自己的边界能力(各种边界条件需要测试)

二:思路

  1. 最近最少使用:

最近最少使用 翻译下:把最后一个不使用的给踢出去

维护一个队列

使用的放到队列的前头

队尾永远是最近最少使用的

翻译:使用了就放队列前头,想移除就移除队尾

  1. 如何实现队列,O(1) 的复杂度

首先想到的是链表,这里使用最普通的 listNode的结构体

java 复制代码
class ListNode {
    int val;
    ListNode next;
    ListNode parent;

    public ListNode(int val) {
        this.val = val;
        this.next = null;
        this.parent = null;
    }
}

三:上代码

代码:

  • 类代码
  • 测试代码

3.1:类代码

java 复制代码
import java.util.HashMap;
import java.util.Map;

public class LRUCache {

	// 初始化的容量
    private final int capacity;

	// 元数据
    private final Map<Integer, Integer> metaMap;

	// 用于记录 key 和队列的关系
    private final Map<Integer, ListNode> metaLinkedMap;

	// 最后一个结点
    private ListNode lastNode;

	// 头结点
    private final ListNode headNode;

    public LRUCache(int capacity) {
        this.capacity = capacity;
        metaMap = new HashMap<>();
        metaLinkedMap = new HashMap<>();
        // 请注意!!! 这里我太笨了,我这里前两个结点都是头结点。这样有利于我个人的思考 !!!!!
        ListNode dataNode = new ListNode(0);
        headNode = new ListNode(0);
        headNode.next = dataNode;
    }

    // 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1
    public int get(int key) {
        if (metaMap.containsKey(key)) {
            // 调整频率
            adjustExistNodeSort(key);

            return metaMap.get(key);
        }
        return -1;
    }

    // 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字
    public void put(int key, int value) {
        if (metaMap.containsKey(key)) {
            // 更新热点数据
            adjustExistNodeSort(key);

            // 替换数据
            metaMap.put(key, value);
        } else {
            if (metaMap.size() == capacity) {
                // 需要移除数据
                removeLastNode();
            }

            ListNode putNode = new ListNode(key);

            // 更新热点数据
            adjustNewNodeSort(putNode);

            // 初始化信息
            metaMap.put(key, value);
            metaLinkedMap.put(key, putNode);
        }
    }

    /**
     * 排序一个已经存在的结点
     * @param key 已经存在的key
     */
    private void adjustExistNodeSort(Integer key) {
        ListNode hotNode = metaLinkedMap.get(key);
        ListNode oldHeadNode = headNode.next.next;

        if (hotNode == oldHeadNode){
            return;
        }

        hotNode.parent.next = hotNode.next;
        if (hotNode.next != null){
            hotNode.next.parent = hotNode.parent;
        }

        if (lastNode == hotNode && metaMap.size() != 1) {
            lastNode = hotNode.parent;
        }

        if (oldHeadNode != null) {
            oldHeadNode.parent = hotNode;
            hotNode.next = oldHeadNode;
        }
        headNode.next.next = hotNode;
        hotNode.parent = headNode.next;
    }


    /**
     * 调整一个新结点的排序
     * @param putNode 新节点
     */
    private void adjustNewNodeSort(ListNode putNode) {
        // 初始化末尾节点
        if (lastNode == null || metaMap.size() == 0) {
            lastNode = putNode;
        }

        // 放到头节点
        ListNode oldHeadNode = headNode.next.next;

        if (oldHeadNode != null) {
            oldHeadNode.parent = putNode;
            putNode.next = oldHeadNode;
        }

        headNode.next.next = putNode;
        putNode.parent = headNode.next;

    }

    /**
     * 移除最后一个元素
     */
    private void removeLastNode() {
        int lastVal = lastNode.val;
        metaMap.remove(lastVal);
        metaLinkedMap.remove(lastVal);
        lastNode = lastNode.parent;
        lastNode.next = null;
    }
}

class ListNode {
    int val;
    ListNode next;
    ListNode parent;

    public ListNode(int val) {
        this.val = val;
        this.next = null;
        this.parent = null;
    }
}

3.2: 测试代码

java 复制代码
import java.util.HashSet;
import java.util.Set;

// Press Shift twice to open the Search Everywhere dialog and type `show whitespaces`,
// then press Enter. You can now see whitespace characters in your code.
public class Main {
    public static void main(String[] args) {

        LRUCache lruCache = new LRUCache(1);
        lruCache.get(6);
        lruCache.get(8);

        lruCache.put(12,1);

        lruCache.get(2);

        lruCache.put(15,11);

        lruCache.put(5,2);
        lruCache.put(1,15);
        lruCache.put(4,2);

        lruCache.get(5);
        lruCache.put(15,15);
    }
}
相关推荐
wjs20242 小时前
状态模式(State Pattern)
开发语言
我命由我123452 小时前
Kotlin 数据容器 - List(List 概述、创建 List、List 核心特性、List 元素访问、List 遍历)
java·开发语言·jvm·windows·java-ee·kotlin·list
liulilittle2 小时前
C++ TAP(基于任务的异步编程模式)
服务器·开发语言·网络·c++·分布式·任务·tap
励志要当大牛的小白菜4 小时前
ART配对软件使用
开发语言·c++·qt·算法
qq_513970444 小时前
力扣 hot100 Day56
算法·leetcode
武子康4 小时前
Java-80 深入浅出 RPC Dubbo 动态服务降级:从雪崩防护到配置中心秒级生效
java·分布式·后端·spring·微服务·rpc·dubbo
爱装代码的小瓶子6 小时前
数据结构之队列(C语言)
c语言·开发语言·数据结构
爱喝矿泉水的猛男7 小时前
非定长滑动窗口(持续更新)
算法·leetcode·职场和发展
YuTaoShao7 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
源码_V_saaskw7 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友