【数据结构与算法】LRU Cache

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

🌠作者@阿亮joy.
🎆专栏《数据结构与算法要啸着学》
🎇座右铭每个优秀的人都有一段沉默的时光那段时光是付出了很多努力却得不到结果的日子我们把它叫做扎根
在这里插入图片描述


目录

👉LRU Cache👈

什么是LRU Cache

LRU 是 Least Recently Used 的缩写意思是最近最少使用它是一种 Cache 替换算法。 什么是Cache狭义的 Cache 指的是位于 CPU 和主存间的快速 RAM随机存取存储器 通常它不像系统主存那样使用 DRAM 技术而使用昂贵但较快速的 SRAM 技术。 广义上的Cache 指的是位于速度相差较大的两种硬件之间 用于协调两者数据传输速度差异的结构。除了 CPU与 主存之间有 Cache 内存与硬盘之间也有 Cache乃至在硬盘与网络之间也有某种意义上 Cache称为 Internet 临时文件夹或网络内容缓存等。

在这里插入图片描述
在这里插入图片描述
Cache 的容量有限因此当 Cache 的容量用完后而又有新的内容需要添加进来时 就需要挑选并舍弃原有的部分内容从而腾出空间来放新内容。LRU Cache 的替换原则就是将最近最少使用的内容替换掉。其实LRU 译成最久未使用会更形象 因为该算法每次替换掉的就是一段时间内最久没有使用过的内容。

LRU Cache的实现

实现 LRU Cache 的方法和思路很多但是要保持高效实现O(1) 的 put 和 get那么使用双向链表和哈希表的搭配是最高效和经典的。使用双向链表是因为双向链表可以实现任意位置 O(1) 的插入和删除使用哈希表是因为哈希表的增删查改也是 O(1)。

在这里插入图片描述

LRU 缓存

在这里插入图片描述

splice 函数可以转移链表中的节点

在这里插入图片描述

哈希表能够保证查找和更新 key 值对应的 value 的时间复杂度为 O(1)也就是能保证 get。那关键点是如何保证 LRU 呢如果 key 值在哈希表中那么就 key 值就是最经常访问的值需要将它放到双向链表的头部假设双向链表尾部的数据是最近最少用的数据。因为我们并不知道 key 值在双向链表中的位置那就无法做到 O(1) 的时间复杂度将 key 值放到链表的头部。那如何解决呢我们做到的是找到 key 值就能够找到 key 值在双向链表中的位置。那么我们可以让哈希表存的是 key 值和 key 值在双向链表中的位置迭代器双向链表存储是键值对pair<key, value>这样就能够保证 LRU Cache 了通过 splice 来调整 key 值在链表中的位置。

在这里插入图片描述

class LRUCache 
{
public:
    LRUCache(int capacity) 
        : _capacity(capacity)
    {}
    
    int get(int key) 
    {
        auto ret = _hashMap.find(key);
        // 哈希表中有key
        if(ret != _hashMap.end())
        {
            // 更新key的位置
            // 1.erase + push_front 更新迭代器,原迭代器失效
            // 2.splice 将节点转移到头部
            ListIterator it = ret->second;
            _LRUList.splice(_LRUList.begin(), _LRUList, it);
            
            return it->second; 
        }
        else
            return -1;
    }
    
    void put(int key, int value) 
    {
        // 1.新增 2.更新
        auto ret = _hashMap.find(key);
        if(ret == _hashMap.end())   // 哈希表中没有key
        {
            // 满了,先删除最近最少用的数据
            if(_capacity == _hashMap.size())
            {
                pair<int, int> LRUData = _LRUList.back();
                _hashMap.erase(LRUData.first);
                _LRUList.pop_back();
            }
            _LRUList.push_front(make_pair(key, value));
            _hashMap[key] = _LRUList.begin();
        }
        else
        {
            // 更新key对应的值
            ListIterator it = ret->second;
            it->second = value;

            // 更新key对应值的位置
            // 1.erase + push_front 更新迭代器,原迭代器失效
            // 2.splice 将节点转移到头部
            _LRUList.splice(_LRUList.begin(), _LRUList, it);
        }
    }
private:
    typedef list<pair<int, int>>::iterator ListIterator;
    // 哈希表做到查找和更新的时间复杂度为O(1)
    // 哈希表中存的是key和key在_LRUList中的位置(迭代器)
    unordered_map<int, ListIterator> _hashMap;
    // LRU假设链表尾部的数据是最近最少用的数据
    // _LRUList中存储的是键值对pair
    list<pair<int, int>> _LRUList;
    size_t _capacity;   // 容量
};

在这里插入图片描述

👉总结👈

本篇博客主要讲解了什么是 LRU Cache 以及如何设计 LRU Cache等。那么以上就是本篇博客的全部内容了如果大家觉得有收获的话可以点个三连支持一下谢谢大家💖💝❣️

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6