LRU Cache的数据结构选择以及实现

2023-10-29

LRU

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

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

LRU Cache的数据结构选择

首先要保证put和get 操作时O(1),其次还要保持LRU特性。

综合各种数据结构,我们采用以下数据结构来实现。

list<pair<int, int>> _list;    // 将最近用过的往链表的投上移动,保持LRU

// 使用unordered_map,让搜索效率达到O(1)
unordered_map<int, list<pair<int, int>>::iterator> _hashmap; 

size_t _capacity; // 容量大小,超过容量则换出,保持LRU

LRU Cache的实现

class LRUCache {
public:
LRUCache(int capacity) {
_capacity = capacity;
} 

int get(int key) {
// 如果key对应的值存在,则listit取出,这里就可以看出hashmap的value存的是list的
iterator的好处:找到key
// 也就找到key存的值在list中的iterator,也就直接删除,再进行头插,实现O(1)的数据
挪动。
auto hashit = _hashmap.find(key);
if(hashit != _hashmap.end())
{
auto listit = hashit->second;
pair<int, int> kv = *listit; 

_list.erase(listit);
_list.push_front(kv);
_hashmap[key] = _list.begin();
return kv.second;
}
else
{
return -1;
}
} 

void put(int key, int value) {
// 1.如果没有数据则进行插入数据
// 2.如果有数据则进行数据更新
auto hashit = _hashmap.find(key);
if(hashit == _hashmap.end())
{
// 插入数据时,如果数据已经达到上限,则删除链表头的数据和hashmap中的数据,两个
删除操作都是O(1)
if(_list.size() >= _capacity)
{
_hashmap.erase(_list.back().first);
_list.pop_back();
} 

_list.push_front(make_pair(key,value));
_hashmap[key] = _list.begin();
}
else
{
// 再次put,将数据挪动list前面
auto listit = hashit->second;

pair<int, int> kv = *listit;
kv.second = value; 

_list.erase(listit);
_list.push_front(kv);
_hashmap[key] = _list.begin();
}}
 

private:
list<pair<int, int>> _list; // 将最近用过的往链表的投上移动,保持LRUsize_t _capacity; // 容量大小,超过容量则换出,保持LR
 

unordered_map<int, list<pair<int, int>>::iterator> _hashmap;// 使用unordered_map,让搜索效率达到O(1)// 需要注意:这里最巧的设计就是将unordered_map的value type放成list<pair<int,int>>::iterator,因为这样,当get一个已有的值以后,就可以直接找到key在list中对应的
iterator,然后将这个值移动到链表的头部,保持LRU。
};
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

LRU Cache的数据结构选择以及实现 的相关文章

  • 当我在组合框中选择一个项目时,如何防止 TextChanged 事件?

    我有一个TextChanged http msdn microsoft com en us library system windows forms control textchanged aspx我的事件ComboBox http msd
  • GetType() 在 Type 实例上返回什么?

    我在一些调试过程中遇到了这段代码 private bool HasBaseType Type type out Type baseType Type originalType type GetType baseType GetBaseTyp
  • 在c#中执行Redis控制台命令

    我需要从 Redis 控制台获取 客户端列表 输出以在我的 C 应用程序中使用 有没有办法使用 ConnectionMultiplexer 执行该命令 或者是否有内置方法可以查找该信息 CLIENT LIST是 服务器 命令 而不是 数据库
  • File.AppendText 尝试写入错误的位置

    我有一个 C 控制台应用程序 它作为 Windows 任务计划程序中的计划任务运行 此控制台应用程序写入日志文件 该日志文件在调试模式下运行时会创建并写入应用程序文件夹本身内的文件 但是 当它在任务计划程序中运行时 它会抛出一个错误 指出访
  • 为什么可以通过ref参数修改readonly字段?

    考虑 class Foo private readonly string value public Foo Bar ref value private void Bar ref string value value hello world
  • 识别 Visual Studio 中的重载运算符 (c++)

    有没有办法使用 Visual Studio 快速直观地识别 C 中的重载运算符 在我看来 C 中的一大问题是不知道您正在使用的运算符是否已重载 Visual Studio 或某些第三方工具中是否有某些功能可以自动突出显示重载运算符或对重载运
  • 打破 ReadFile() 阻塞 - 命名管道 (Windows API)

    为了简化 这是一种命名管道服务器正在等待命名管道客户端写入管道的情况 使用 WriteFile 阻塞的 Windows API 是 ReadFile 服务器已创建启用阻塞的同步管道 无重叠 I O 客户端已连接 现在服务器正在等待一些数据
  • 使用valgrind进行GDB远程调试

    如果我使用远程调试gdb我连接到gdbserver using target remote host 2345 如果我使用 valgrind 和 gdb 调试内存错误 以中断无效内存访问 我会使用 target remote vgdb 启动
  • 如何在 Qt 应用程序中通过终端命令运行分离的应用程序?

    我想使用命令 cd opencv opencv 3 0 0 alpha samples cpp cpp example facedetect lena jpg 在 Qt 应用程序中按钮的 clicked 方法上运行 OpenCV 示例代码
  • 为什么这个二维指针表示法有效,而另一个则无效[重复]

    这个问题在这里已经有答案了 这里我编写了一段代码来打印 3x3 矩阵的对角线值之和 这里我必须将矩阵传递给函数 矩阵被传递给指针数组 代码可以工作 但问题是我必须编写参数的方式如下 int mat 3 以下导致程序崩溃 int mat 3
  • 为什么我的单选按钮不起作用?

    我正在 Visual C 2005 中开发 MFC 对话框应用程序 我的单选按钮是 m Small m Medium 和 m Large 它们都没有在我的 m Summary 编辑框中显示应有的内容 可能出什么问题了 这是我的代码 Pizz
  • C++ 中的双精度型数字

    尽管内部表示有 17 位 但 IEE754 64 位 浮点应该正确表示 15 位有效数字 有没有办法强制第 16 位和第 17 位为零 Ref http msdn microsoft com en us library system dou
  • 使 Guid 属性成为线程安全的

    我的一个类有一个 Guid 类型的属性 该属性可以由多个线程同时读写 我的印象是对 Guid 的读取和写入不是原子的 因此我应该锁定它们 我选择这样做 public Guid TestKey get lock testKeyLock ret
  • String.Empty 与 "" [重复]

    这个问题在这里已经有答案了 可能的重复 String Empty 和 有什么区别 https stackoverflow com questions 151472 what is the difference between string
  • 将数组作为参数传递

    如果我们修改作为方法内参数传递的数组的内容 则修改是在参数的副本而不是原始参数上完成的 因此结果不可见 当我们调用具有引用类型参数的方法时 会发生什么过程 这是我想问的代码示例 using System namespace Value Re
  • 这个可变参数模板示例有什么问题?

    基类是 include
  • 我可以在“字节数”设置为零的情况下调用 memcpy() 和 memmove() 吗?

    当我实际上没有什么可以移动 复制的时候 我是否需要处理这些情况memmove memcpy 作为边缘情况 int numberOfBytes if numberOfBytes 0 memmove dest source numberOfBy
  • 为boost python编译的.so找不到模块

    我正在尝试将 C 代码包装到 python 中 只需一个类即可导出两个函数 我编译为map so 当我尝试时import map得到像噪音一样的错误 Traceback most recent call last File
  • 是否可以在不连接数据库的情况下检索 MetadataWorkspace?

    我正在编写一个需要遍历实体框架的测试库MetadataWorkspace对于给定的DbContext类型 但是 由于这是一个测试库 我宁愿不连接到数据库 它引入了测试环境中可能无法使用的依赖项 当我尝试获取参考时MetadataWorksp
  • 如何将十六进制字符串转换为无符号长整型?

    我有以下十六进制值 CString str str T FFF000 如何将其转换为unsigned long 您可以使用strtol作用于常规 C 字符串的函数 它使用指定的基数将字符串转换为 long long l strtol str

随机推荐

  • Python正则表达式学习(3)——re.compile()

    re compile pattern flags 0 将正则表达式 pattern 编译为正则表达式对象 可用于使用其 match 和search 方法进行匹配 顺序 prog re compile pattern result prog
  • Pinctrl子系统之一了解基础概念

    1 Linux Pinctrl子系统简介 在许多soc内部都包含有pin控制器 通过pin控制器的寄存器 我们可以配置一个或者一组引脚的功能和特性 在软件方面 Linux内核提供了pinctrl子系统 目的是为了统一各soc厂商的pin脚管
  • TreeView —WPF—MVVM—HierarchicalDataTemplate

    摘要 采用HierarchicalDataTemplate数据模板和treeview在MVVM模式下实现行政区划树 支持勾选 勾选父节点 子节点回全部自动勾选 子节点部分勾选时 父节点半勾选 子节点全部勾选时 父节点勾选 反之亦然 Hier
  • 吴恩达9.3 反向传播的直观理解

    为了更好地理解反向传播算法 我们再来仔细研究一下前向传播的原理 前向传播算法 反向传播算法做的是
  • Qt基础——UI文件.h文件说明

    首先 需要使用Qt Designer设计你的UI界面 Qt号称是跨平台应用程序和UI开发框架 所以其自带的UI设计器 即Qt Designer 功能也非常强大 除了通常用的如Button List等组件外面 使用Qt Designer做UI
  • mac出现wifi没有ip地址无法接入互联网

    问题 情况 wifi已经输入密码正确 但是中间出现灰色的wifi图标 还有一个叹号 说是没有IP地址 解决方法 1 试过重启 2 试过删掉该网络再重新输入密码 3 试过删掉WiFi一栏 来自百度 最佳答案 1 首先打开偏好设置 点击网络选项
  • 用Python赚钱的方法有哪些?

    很多人想知道用Python赚钱的方法有哪些 Python很容易使用 应用性较强 可以通过使用Python开发小程序 抓取数据 游戏开发 兼职编程老师 发展副业的方式来赚钱 文末有福利 用Python赚钱的方法 1 某宝搜python程序 可
  • java多线程设计模式

    1 I O处理比较花费时间 故把执行I O处理和非IO处理的线程分开 CPU执行速度很快 而内存的写入 读取很慢 所以有关CPU和内存交互会降低指令的速度 2 start方法运行有2个步骤 启动新的线程 运行new对象的run方法 3 所有
  • AD19 PCB设计导入元件库、导出pdf、定义板子形状、生成元件库、铺铜基本操作总结

    导入元件库 1 点击右侧components 2 右键 然后选择 Add or Remove Libraries 3 点击从文件安装 4 选择库文件 导出PDF 导出原理图或者pcb等信息pdf操作 文件 gt 智能pdf 定义板子形状 使
  • 慕课第四周第7题 出租车计价

    出租车计价 4分 题目内容 已知某城市普通出租车收费标准为 起步里程为3公里 起步费为8元 10公里以内超过起步里程的部分 每公里加收2元 超过10公里以上的部分加收50 的回空补贴费 即每公里3元 出租车营运过程中 因堵车和乘客要求临时停
  • eigen 教程和指南

    转自 http eigen tuxfamily org dox 2 0 TutorialCore html https blog csdn net xuezhisdc article details 54619853 固定大小的矩阵和向量
  • 两个多项式的相加操作 C语言(链式存储结构)

    内容 完成两个多项式的相加操作 已知有两个多项式P x Q x 设计算法实现P x Q x 运算 而且对加法运算不重新开辟存储空间 要求用链式存储结构 例如 P x 5x 3 2x 1 Q x 3x 3 x 2 2x 3 其计算输出结果为
  • RHEL8、CentOS8配置本地YUM源

    1 挂载光盘镜像到一个指定的目录 2 创建一个仓库配置文件 3 编辑 etc fstab配置文件 让光盘开机自动挂载 4 使用yum dnf命令来安装软件 仓库名称 具有唯一性的标识名称 不应与其他软件仓库发生冲突 描述信息 name 可以
  • 如何将JSON字符串转化成对象

    在这里只能使用ObjiectMapper这个类才能将Json字符串转成对象的格式进行输出 话不多说 直接上代码 实体类 实体类 Setter Getter public class UserInfo implements Serializa
  • 搭建个人备忘录中心服务memos、轻量级笔记服务

    目录 一 源码 二 官网 三 搭建 四 使用 一 源码 GitHub usememos memos A privacy first lightweight note taking service Easily capture and sha
  • 计算机网络 第四章网络层(6)网络地址转换 NAT多协议标记交换 MPLS MPLS 协议的基本原理

    关注公众号凡花花的小窝 收获更多的考研计算机专业编程相关的资料 4 8 2 网络地址转换 NAT 问题 在专用网上使用专用地址的主机如何与互联网上的主机通信 并不需要加密 解决 再申请一些全球 IP 地址 但这在很多情况下是不容易做到的 采
  • 机器学习 :训练集、验证集、测试集分配比例

    根据 统计学习方法 中的观点 如果给定的样本数据充足 进行模型选择的一种简单方法是随机地将数据集切分成三部分 分别为训练集 training set 验证集 validation set 和测试集 test set 训练集用来训练模型 验证
  • JS解析详细分析

    1 确定js的位置 1 1 观察按钮的绑定js事件 通过点击按钮 然后点击Event Listener 部分网站可以找到绑定的事件 对应的 只需要点击即可跳转到js的位置 1 2 通过search all file 来搜索 部分网站的按钮可
  • 如何检查 Linux 中的程序和监听的端口

    在 Linux 或者类 Unix 中 我该如何检查某个端口是否被占用 我又该如何验证 Linux 服务器中有哪些端口处于监听状态 验证哪些端口在服务器的网络接口上处于监听状态是非常重要的 你需要注意那些开放端口来检测网络入侵 除了网络入侵
  • LRU Cache的数据结构选择以及实现

    LRU LRU是Least Recently Used的缩写 意思是最近最少使用 它是一种Cache替换算法 什么是Cache 狭义的Cache指的是位于CPU和主存间的快速RAM 通常它不像系统主存那样使用DRAM技术 而使用昂贵但较快速