LRU算法

LRU是LeastRecentlyUsed的缩写,是一种页面置换算法,用于内存管理。文章介绍了使用栈和哈希双向链表两种方案实现LRU缓存,其中哈希链表方案能保证O(1)的插入和删除操作,优化性能。LRUCache类的实现包括get和put方法,以及makeRecently函数,用于维护最近使用的页面顺序。

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

一、简介

LRU是Least Recently Used的缩写,即最近最少使用页面置换算法,是为虚拟页式存储管理服务的,是根据页面调入内存后的使用情况进行决策了。LRU算法就是将最近最久未使用的页面予以淘汰。

操作系统里,在内存不够的场景下,淘汰旧内容的策略。在计算机体系里,最大最可靠的存储是硬盘,容量大、内容可固化,但访问速度慢,所以需要将适用的内容载入内存。内存速度快但容量有限,新的内容被载入,旧的内容就要被淘汰。

二、原理

方案1、栈

用一个栈来表示正在使用的页面的页面号,当一个新的进程访问某页面时,便将该页面号压入栈顶,其他的页面号往栈底移,如果内存不够,则将栈底的页面号移除。这样,栈顶始终是最新被访问的页面的编号,而栈底则是最近最久未访问的页面的页面号

这样设计可能问题很多,这段内存按照访问时间进行了排序,会有大量的内存拷贝操作,所以性能肯定是不能接受的。

设计一个LRU缓存,使得放入和移除都是 O(1) 的,我们需要把访问次序维护起来,但是不能通过内存中的真实排序来反应,有一种方案就是哈希双向链表(方案2)。

方案2、哈希链表

哈希表存储的是页面的key-value,哈希链表中的key-value被一个链条串起来,每一个Key-Value都具有它的前驱Key-Value、后继Key-Value,就像双向链表中的节点一样。这样一来,原本无序的哈希表拥有了固定的排列顺序。

使用 HashMap 存储 key,这样可以做到 save 和 get key的时间都是 O(1),而 HashMap 的 Value 指向双向链表实现的 LRU 的 Node 节点

步骤:

  1.  save(key, value),首先在 HashMap 找到 Key 对应的节点,如果节点存在,更新节点的值,并把这个节点移动队头。如果不存在,需要构造新的节点,并且尝试把节点塞到队头,如果LRU空间不足,则通过 tail 淘汰掉队尾的节点,同时在 HashMap 中移除 Key。
  2. get(key),通过 HashMap 找到 LRU 链表节点,把节点插入到队头,返回缓存的值。

 

/**
 * @param {number} capacity
 */
var LRUCache = function(capacity) {
    this.cap = capacity;
    this.cache = new Map();
};

/** 
 * @param {number} key
 * @return {number}
 */
LRUCache.prototype.get = function(key) {
    if (!this.cache.has(key)) {
        return -1;
    }
    // 将 key 变为最近使用
    this.makeRecently(key);
    return this.cache.get(key);
};

/** 
 * @param {number} key 
 * @param {number} value
 * @return {void}
 */
LRUCache.prototype.put = function(key, val) {
    if (this.cache.has(key)) {
        // 修改 key 的值
        this.cache.set(key, val);
        // 将 key 变为最近使用
        this.makeRecently(key);
        return;
    }

    if (this.cache.size >= this.cap) {
        // 链表头部就是最久未使用的 key
        const oldestKey = this.cache.keys().next().value;
        this.cache.delete(oldestKey);
    }
    // 将新的 key 添加链表尾部
    this.cache.set(key, val);
};

LRUCache.prototype.makeRecently = function(key) {
    const val = this.cache.get(key);
    // 删除 key,重新插入到队尾
    this.cache.delete(key);
    this.cache.set(key, val);
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * var obj = new LRUCache(capacity)
 * var param_1 = obj.get(key)
 * obj.put(key,value)
 */

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值