【LeetCode】LRU缓存

本文介绍了LeetCode中LRU缓存的问题,分析了LRU的最近最久未使用原则,并提供了Java和JavaScript两种实现方式,Java实现利用哈希表和双向链表,JavaScript则利用Map的数据结构。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:LRUCache

分析:LRU最近最久未使用,可以把每次刚被访问过的节点从缓存区的左端加入,那么缓存区右端就是最近最久未使用的节点,缓存区满了的话就从右端删除。get时,就把节点从原位置移除,再从左端加入缓存区;set时,就把节点从左端加入缓存区,如果缓存区满了,就从右端移除一个节点。

Java实现:哈希表+双向链表:

虽然有LinkedHashMap结构,但还是需要自己实现双向链表结构。

代码如下:

//LRU缓存类:双向链表+HashMap(虽然java有自带的LinkedHashMap(结合了哈希表与双向链表结构),但还是希望能够自己实现一个双向链表)
//最近被访问过的节点在链表头部
public class LRUCache {
//    内部还有一个类
    class DoubleLinkedList{
        // 链表节点data区
        int key;
        int value;
        // 链表节点指针区
        DoubleLinkedList prev;
        DoubleLinkedList next;
        // 无参构造函数
        private DoubleLinkedList(){};
        // 构造函数
        private DoubleLinkedList(int key,int value){
            this.key=key;
            this.value=value;
        }
    }
//    LRUCache类的数据
    private int size;
    private int capacity;
    private Map<Integer,DoubleLinkedList> cache=new HashMap<>();
    // 虚拟头尾节点,(添加和删除操作时不必再判断是否有相邻节点)
    private DoubleLinkedList head,tail;

//    构造函数(初始化)
    public LRUCache(int capacity) {
        this.size=0;
        this.capacity=capacity;
        head=new DoubleLinkedList();
        tail=new DoubleLinkedList();
        head.next=tail;
        tail.prev=head;
    }
//    链表data域中的key和哈希表中的key值是相等的。(方便通过节点查找对应的key-value)
    public int get(int key) {
        DoubleLinkedList node=cache.get(key);
        if(node==null)
            return -1;
        // 把刚访问过的节点移动到链表头部
        moveToHead(node);
        return node.value;
    }
    public void put(int key, int value) {
        DoubleLinkedList node=cache.get(key);
        if(node==null){
            // 创建新节点
            node=new DoubleLinkedList(key,value);
            // 加入哈希表
            cache.put(key,node);
            // 加入链表头部
            addToHead(node);
            //  还要判断当前size
            size++;
            if(size>capacity){
                // 删除链表尾部节点
                DoubleLinkedList tailNode=removeTail();
                //  并从哈希表中删除
                cache.remove(tailNode.key);
                size--;
            }
        }
        else{
            // 更新值
            node.value=value;
            // 移动到链表头部
            moveToHead(node);
        }
    }
    private void addToHead(DoubleLinkedList node){
        node.next=head.next;
        head.next.prev=node;
        head.next=node;
        node.prev=head;
    }
//    包括从当前位置删除和添加到链表头部
    private void moveToHead(DoubleLinkedList node){
        removeNode(node);
        addToHead(node);
    }
    private void removeNode(DoubleLinkedList node){
        node.prev.next=node.next;
        node.next.prev=node.prev;
        node.next=null;
        node.prev=null;
    }
    private DoubleLinkedList removeTail(){
        DoubleLinkedList node=tail.prev;
        node.prev.next=tail;
        tail.prev=node.prev;
        return node;
    }
}

JavaScript实现:Map(Map的set方法加入数据是顺序加入的,即从尾部加入)

代码如下:

/**
 * @param {number} capacity
 */
// 最近被访问过的节点在map尾部
// 构造函数
var LRUCache = function(capacity) {
    this.capacity=capacity;
    // map的set方法是按照顺序插入的(相当于从尾部插入)
    this.map=new Map();
};

/** 
 * @param {number} key
 * @return {number}
 */
LRUCache.prototype.get = function(key) {
    if(this.map.has(key)){
        let value=this.map.get(key);
        // 删除节点
        this.map.delete(key);
        // 再从尾部插入节点
        this.map.set(key,value);
        return value;
    }
    return -1;
};

/** 
 * @param {number} key 
 * @param {number} value
 * @return {void}
 */
LRUCache.prototype.put = function(key, value) {
    if(this.map.has(key)){
        this.map.delete(key);   
    }
    this.map.set(key,value);
    if(this.map.size>this.capacity){
        // 删除map中的第一个元素
        this.map.delete(this.map.keys().next().value);
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值