力扣146:LRU缓存

一,简介

LRU(Least Recently Used),最近最少使用算法,从名字上可能不太好理解,我是这样记的:LRU算法,淘汰最近一段时间内,最久没有使用过的数据

本文使用HashMap和双向链表来实现LRU算法,原理如下图所示:

其中:

  1.双向链表的主要功能是维护Node节点的顺序;

  2.HashMap的主要功能是存储K-V缓存项,另外V为Node类型,也就是能通过key快速找到Node节点(快速定位到该Node节点在双链表中的位置,而不用遍历双链表来找该Node节点);

  比如我要删除key为100的缓存项,那么根据HashMap的key快速找到100对应的node节点,然后在双向链表中将节点进行删除(修改前后Node的指针即可)。

  当然可以将双向链表替换为单链表(也能保存顺序),但是这样会有问题:

  1.每次定位到要删除的node后,都要从头开始再遍历一次链表,找到要删除的节点的前一个节点,然后修改指针进行删除节点操作

  2.每次查询到key对应的value后,需要将对应的Node移动到第一个位置(表示最近访问),那么有需要遍历一遍链表,然后在修改指针将节点进行移动

  鉴于以上原因,所以不考虑使用单链表。

二,实现(CPP实现)

#include<unordered_map>
using namespace std;
class LRUCache {
    //LRU核心思想,维护一个大小为n的缓存,内部数据按照使用时间由近到远排列,当插入数据时,超过规定大小,则删除最后的元素。任何操作(访问,修改)都会让这个数据位置放在第一位
public:

    //定义双链表
    struct Node{
        //双向链表使用的目的是便于访问链表的头尾部分,无需遍历
        int key,value;
        Node* left ,*right;
        Node(int _key,int _value): key(_key),value(_value),left(NULL),right(NULL){}
    }*L,*R;//双链表的最左和最右节点,不存贮值。
    int n;
    unordered_map<int,Node*>hash;   //哈希表主要负责更快的找到指定节点,无需遍历双向链表,使缓存提速

    void remove(Node* p)
    {
        //删除指定节点函数
        p->right->left = p->left;   //指定节点的下一个节点的前指针指向前前节点
        p->left->right = p->right;   //指定节点的前一个节点的后指针指向后后节点
    }
    void insert(Node *p)
    {
        //将指定节点插入至双向链表头(l,r维护双向链表的头尾指针)
        p->right = L->right;    //此节点的后指针指向头指针的后一节点
        p->left = L;    //此节点的左指针指向头节点
        L->right->left = p; //头指针后一节点的前指针指向此节点
        L->right = p;   //头指针的后指针指向此节点
    }
    LRUCache(int capacity) {
        //初始化LRU缓存
        n = capacity;
        L = new Node(-1,-1),R = new Node(-1,-1);
        L->right = R;
        R->left = L;
    }

    int get(int key) {
        if(hash.count(key) == 0) return -1; //不存在关键字 key 
        auto p = hash[key]; //从哈希表取出该节点
        remove(p);  //移除该节点
        insert(p);//将当前节点放在双链表的第一位
        return p->value;
    }

    void put(int key, int value) {
        if(hash.count(key)) //如果key存在,则修改对应的value
        {
            auto p = hash[key]; //从哈希表取出该节点
            p->value = value;   //修改
            remove(p);  //移除该节点
            insert(p);//将当前节点放在双链表的第一位
        }
        else
        {
            if(hash.size() == n) //如果缓存已满,则删除双链表最右侧的节点
            {
                auto  p = R->left;  //获取最后节点
                remove(p);  //移除此节点
                hash.erase(p->key); //更新哈希表
                delete p; //释放内存
            }
            //否则,插入(key, value)
            auto p = new Node(key,value);
            hash[key] = p;
            insert(p);  //将当前节点放在双链表的第一位
        }
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Nathaniel333

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值