【高阶数据结构】LRU Cache

news/2024/11/27 3:54:06/

> 作者:დ旧言~
> 座右铭:松树千年终是朽,槿花一日自为荣。

> 目标:了解什么是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)。

说明:

  • 保证查找和更新 key值对应的value的时间复杂度为O(1), 也就是保证了get,但是不能保证LRU,因为无法从哈希表中知道知道key值在双向链表中的位置,因此无法用O(1)的时间复杂度来将key值放到链表的头部。
  • 我们可以让哈希表中存储key值和key值在双向链表中的位置,因此可以让哈希表中存储key值和key值在双向链表中的位置——迭代器,双向链表存储的是键值对pair<key, value>,这样就可以保证 LRU Cache了。

代码实现:

class LRUCache {
public:LRUCache(int capacity):_capacity(capacity){}int get(int key) {auto ret = _hashMap.find(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()) // 新增数据{// 容量已满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对应值的位置——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;list<pair<int,int>> _LRUList;size_t _capacity; //容量
};

三、LRU Cache的OJ

LRU缓存. - 力扣(LeetCode)

class LRUCache {
public:LRUCache(int capacity):_capacity(capacity){}int get(int key) {auto ret = _hashMap.find(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()) // 新增数据{// 容量已满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对应值的位置——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;list<pair<int,int>> _LRUList;size_t _capacity; //容量
};

四、结束语 

今天内容就到这里啦,时间过得很快,大家沉下心来好好学习,会有一定的收获的,大家多多坚持,嘻嘻,成功路上注定孤独,因为坚持的人不多。那请大家举起自己的小手给博主一键三连,有你们的支持是我最大的动力💞💞💞,回见。

​​ 


http://www.ppmy.cn/news/1550231.html

相关文章

【Angular】eventDispatcher详解

eventDispatcher 是一种设计模式&#xff0c;用于在对象之间传递事件。它允许对象订阅和发布事件&#xff0c;从而实现松耦合的通信机制。以下是一个详细的解释和示例代码。 1. 基本概念 事件&#xff08;Event&#xff09;&#xff1a;一个动作或状态变化&#xff0c;可以被…

SpringBoot开发——Maven多模块工程最佳实践及详细示例

文章目录 一、前言二、Maven多模块工程的最佳实践1、项目结构清晰2、依赖管理统一3、插件配置统一4、版本控制一致5、模块间通信简化 三、详细示例1、项目结构2、父模块&#xff08;parent&#xff09;的pom.xml文件3、子模块&#xff08;module-api&#xff09;的pom.xml文件4…

【Python】九大经典排序算法:从入门到精通的详解(冒泡排序、选择排序、插入排序、归并排序、快速排序、堆排序、计数排序、基数排序、桶排序)

文章目录 1. 冒泡排序&#xff08;Bubble Sort&#xff09;2. 选择排序&#xff08;Selection Sort&#xff09;3. 插入排序&#xff08;Insertion Sort&#xff09;4. 归并排序&#xff08;Merge Sort&#xff09;5. 快速排序&#xff08;Quick Sort&#xff09;6. 堆排序&…

PyTorch2

Tensor的常见操作&#xff1a; 获取元素值&#xff1a; 注意&#xff1a; 和Tensor的维度没有关系&#xff0c;都可以取出来&#xff01; 如果有多个元素则报错&#xff1b; import torch def test002():data torch.tensor([18])print(data.item())pass if __name__ &qu…

【高阶数据结构】图论

> 作者&#xff1a;დ旧言~ > 座右铭&#xff1a;松树千年终是朽&#xff0c;槿花一日自为荣。 > 目标&#xff1a;了解什么是图&#xff0c;并能掌握深度优先遍历和广度优先遍历。 > 毒鸡汤&#xff1a;有些事情&#xff0c;总是不明白&#xff0c;所以我不会坚持…

单片机结合OpenCV

目录 一、引言 二、单片机结合 OpenCV 的优势 1. 图像识别与处理 2. 目标检测 3. 用户界面开发 4. Linux 在嵌入式系统中的作用 5. 多线程优势 6. 网络编程作用 7. 文件编程功能 三、OpenCV 在单片机上的实现难点 1. 处理能力限制 2. 通信与优化挑战 四、单片机如…

《基于FPGA的便携式PWM方波信号发生器》论文分析(二)——方波信号产生

一、论文概述 基于FPGA的便携式PWM方波信号发生器是一篇由任青颖、庹忠曜、黄洵桢、李智禺和张贤宇 等人发表的一篇期刊论文。该论文主要研究了一种新型的信号发生器&#xff0c;旨在解决传统PWM信号发生器在移动设备信号调控中存在的精准度低和便携性差的问题 。其基于现场可编…

xtu oj Estrella‘s Chocolate

样例输入 2 5 2 5 3 2 4 1 5 3 5 3 2 4 1样例输出 8 5 解题思路&#xff1a;二分法&#xff0c;emm……&#xff0c;感觉挺难想到的。 问题简化 给定一个数组&#xff0c;和一个值k&#xff0c;数组分成k段。要求这k段子段和最大值最小。求出这个值。 1、求出数组中的最大…