数据结构:LRUCache
什么是LRUCache
首先我们来看看什么是cache
缓存(Cache)通常用于两个速度不同的介质之间,以提高数据访问的速度和效率。这里有几个典型的应用场景:
- 处理器和内存之间: 处理器(CPU)的运算速度远快于从内存中读取数据的速度。因此,在CPU和内存之间会有多级缓存(L1、L2、甚至L3缓存),用来临时存储即将被CPU使用的数据和指令。这样做可以大幅减少CPU等待数据的时间,提高整体计算效率。
- 内存和硬盘之间: 内存的访问速度也远快于硬盘(无论是HDD还是SSD)。操作系统会使用一部分内存作为硬盘缓存(有时称为“磁盘缓存”或“缓冲区缓存”),用于临时存储最近访问过的数据和文件。当再次请求这些数据时,可以直接从内存中获得,而不是从较慢的硬盘中读取。
- 数据库系统中: 数据库管理系统(DBMS)也会使用缓存技术来提高查询速度和数据处理效率。缓存可以存储经常访问的查询结果、数据库索引等信息,从而加速后续相同或相似查询的处理速度。
- 网络请求: 在网络请求中,缓存也是提高数据访问速度的重要技术。例如,Web浏览器会缓存访问过的网页资源(如HTML文件、图片等),当再次访问这些资源时,可以直接从本地缓存读取,而不需要重新从网络下载。
cache的核心作用是作为一组缓冲区来降低不同介质之间的速度差异。
那么问题来了,cache满了怎么办?
显然,满了就需要删除掉旧的,替换进去新的内容。
但是该如何替换呢?也就是替换策略是什么样的呢?
目前,最常用的替换策略就是LRU(Least Recently Used),意思是最近最少使用,也就是当cache满了以后,用新的数据替换最近最少使用的数据。
顾名思义,LRUCache就是采用LRU替换策略的cache。
LRUCache的实现
LRUCache的实现,我们以一道leetcode的题目为例
传送门:leetcode链接

cache需要实现的功能主要有查找和插入。
想要实现LRUCache的功能是很简单的,但是,想要实现高效的LRUCache并不简单。
所谓高效,我们定义为,插入和查找的时间复杂度都达到O(1)
LRUCache的结构(核心)
想要查找和插入的时间复杂度为O(1),很显然想到hash表
但是如何实现LRU策略呢?
这里,我们的方法是使用一个list容器
当一个数据被使用之后,立即提到list的头部
这样,list的尾的数据,就是LRU的,即最近最少使用的。
所以,我们的结构真的是下面的样子吗?
class LRUCache
{
private:unordered_map<int,int> _hash;list<pair<int,int>> _list;int _capacity;
};
来,我们思考一下
当我们要修改一个数据的时候,我们是不是要先找到,才能修改
hash表中查找很简单,但是list中查找需要遍历一遍,时间复杂度是O(N),显然,就违背了我们高效的初衷。
那怎么办呢?
LRU没办法实现高效的设计吗?
前人给出了天才般的设计。
class LRUCache {
private:unordered_map<int,list<pair<int,int>>::iterator> _hash;//通过迭代器可以实现//链表的O(1)的查找list<pair<int,int>> _list;//链表的查找是O(N),直接使用链表不行int _capacity;
};
在原来的设计中,hash和list中都存了value,这显然浪费了呀,凭啥要存两次啊,脸大吗?
所以在新的设计中
我们hash表的value不存真正的value,而是存list的迭代器。
这样,list的查找我们就可以借助hash来完成,就将list查找的时间复杂度降到了O(1)
当然这样的设计维护起来肯定是要稍微麻烦一点的,一点修改,就需要两个容器同时维护。
LRUCache的查找
int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
有一处细节需要注意
当我们找到了数据后,代表着这条数据已经使用过,就需要将他提到list的头部,同时hash也要对应修改
其余非常简单,直接看代码即可
int get(int key)
{auto it = _hash.find(key);if(it != _hash.end()){_list.splice(_list.begin(),_list,it->second);_hash[key] = _list.begin();return (it->second)->second;}elsereturn -1;
}
LRUCache的插入
void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
如果key已经存在,那就直接更新即可,更新完后,提到list的头部。
如果key不存在,那就直接插入即可,
1. LRUCache满了,尾删,然后头插
2. LRUCache没满,直接头插
更新list的同时要一起更新hash表
void put(int key, int value)
{auto it = _hash.find(key);if(it != _hash.end())//找到了,直接更新即可{it->second->second = value;_list.splice(_list.begin(),_list,it->second);}else//没找到,要新插入{if(_list.size() == _capacity)//把最近不使用的元素删除掉{pair<int,int> back = _list.back();_list.pop_back();_hash.erase(back.first);}_list.push_front({key,value});_hash[key] = _list.begin(); }
}
完整代码
class LRUCache {
private:unordered_map<int,list<pair<int,int>>::iterator> _hash;//通过迭代器可以实现//链表的O(1)的查找list<pair<int,int>> _list;//链表的查找是O(N),直接使用链表不行int _capacity;
public:LRUCache(int capacity) {_capacity = capacity;}int get(int key) {auto it = _hash.find(key);if(it != _hash.end()){_list.splice(_list.begin(),_list,it->second);_hash[key] = _list.begin();return (it->second)->second;}elsereturn -1;}void put(int key, int value) {auto it = _hash.find(key);if(it != _hash.end())//找到了,直接更新即可{it->second->second = value;_list.splice(_list.begin(),_list,it->second);}else//没找到,要新插入{if(_list.size() == _capacity)//把最近不使用的元素删除掉{pair<int,int> back = _list.back();_list.pop_back();_hash.erase(back.first);}_list.push_front({key,value});_hash[key] = _list.begin(); }}
};/*** Your LRUCache object will be instantiated and called as such:* LRUCache* obj = new LRUCache(capacity);* int param_1 = obj->get(key);* obj->put(key,value);*/
相关文章:
数据结构:LRUCache
什么是LRUCache 首先我们来看看什么是cache 缓存(Cache)通常用于两个速度不同的介质之间,以提高数据访问的速度和效率。这里有几个典型的应用场景: 处理器和内存之间: 处理器(CPU)的运算速度远…...
shell脚本案例:创建用户和组
使用场景 在部署程序时,往往首要任务是创建用户和组。有的程序可能用到的组、用户比较多;且不知道服务器环境是否已经有了所需的组和用户。所以针对这个情况,根据Oracle RAC部署时的实际情况写了个脚本。 Linux版本 脚本代码 #!/bin/bash …...
C++笔试题之实现一个定时器
一.定时器(timer)的需求 1.执行定时任务的时,主线程不阻塞,所以timer必须至少持有一个线程用于执行定时任务 2.考虑到timer线程资源的合理利用,一个timer需要能够管理多个定时任务,所以timer要支持增删任务…...
【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-13
文件下载与邀请翻译者 学习英特尔开发手册,最好手里这个手册文件。原版是PDF文件。点击下方链接了解下载方法。 讲解下载英特尔开发手册的文章 翻译英特尔开发手册,会是一件耗时费力的工作。如果有愿意和我一起来做这件事的,那么ÿ…...
快消零售行业的培训创新:构建在线培训知识库
在快速消费品(FMCG)行业中,员工的培训和发展对于保持竞争力至关重要。随着电子商务的兴起和消费者行为的变化,快消零售行业需要不断适应新的市场趋势。在线培训知识库作为一种有效的培训工具,可以帮助企业提升员工技能…...
【AI开源项目】Botpress - 开源智能聊天机器人平台及其部署方案
文章目录 Botpress 概述Botpress 的定位 Botpress 的主要特点1. OpenAI 集成2. 易于使用3. 定制和扩展性4. 多平台支持5. 集成和扩展 API6. 活跃的社区和详尽的文档 部署方案集成集成开发集成部署机器人示例开发工具代理本地开发先决条件从源代码构建 Botpress 如何解决常见问题…...
一文读懂系列:SSL加密流量检测技术详解
SSL加密流量检测功能的主要目的是为了对加密流量做解密处理,并对解密后的流量做内容安全检查(比如反病毒、入侵防御、URL远程查询、内容过滤、文件过滤和邮件过滤等)和审计(防止信息泄露)。接下来我们详细介绍SSL加密流…...
Android Studio各种历史版本
下载地址:AndroidDevTools - Android开发工具 Android SDK下载 Android Studio下载 Gradle下载 SDK Tools下载...
大数据导论及分布式存储HadoopHDFS入门
思维导图 数据导论 数据是什么? 进入21世纪,我们的生活就迈入了"数据时代" 作为21世纪的新青年,"数据"一词经常出现。 数据无时无刻的在影响着我们的现实生活 什么是数据? 数据又如何影响现实生活? 数据…...
语言模型的采样方法
语言模型的采样方法 语言模型的输出为一个向量,该向量的每一维代表着词典中对应词的概率。 在采用自回归范式的文本生成任务中,语言模型将依次生成一组向量并将其解码为文本。将这组向量解码为文本的过程被成为语言模型解码。 解码过程显著影响着生成文本…...
使用 Nginx 配置真实 IP 地址转发
使用 Nginx 配置真实 IP 地址转发 在许多 web 应用程序中,获取客户端的真实 IP 地址非常重要,尤其是在使用反向代理服务器(如 Nginx)时。本文将指导你如何在 Nginx 中配置 X-Real-IP 和 X-Forwarded-For 头部,以确保你…...
WPF+MVVM案例实战与特效(二十四)- 粒子字体效果实现
文章目录 1、案例效果2、案例实现1、文件创建2.代码实现3、界面与功能代码3、总结1、案例效果 提示:这里可以添加本文要记录的大概内容: 2、案例实现 1、文件创建 打开 Wpf_Examples 项目,在 Views 文件夹下创建窗体界面 ParticleWindow.xaml,在 Models 文件夹下创建粒子…...
Oracle视频基础1.4.3练习
15个视频 1.4.3 できない dbca删除数据库 id ls cd cd dbs ls ls -l dbca# delete a database 勾选 # chris 勾选手动删除数据库 ls ls -l ls -l cd /u01/oradata ls cd /u01/admin/ ls cd chris/ ls clear 初始化参数文件,admin,数据文件#新版本了…...
energy 发布 v2.4.5
更新内容 修复 energy cli install 命令安装开发环境 修复 动态库加载error未暴露 增加 JS ipc.on 监听模式,异步返回结果 修复 energy cli 不能强制退出问题 修复 MacOS 开发模式 debug 时不更新 helper 进程 优化 energy cli 在 MacOS 开发模式和安装包制作 link…...
一文详解工单管理系统,工单系统是什么意思
在现代企业管理中,工单管理系统已经成为提升效率和客户满意度的重要工具。随着企业规模的扩大和业务复杂性的增加,传统的手工工单处理方式已经无法满足企业的需求。本文将详细解析工单管理系统的定义、功能、优势,并推荐一款优秀的工单管理系…...
【无标题】基于SpringBoot的母婴商城的设计与实现
一、项目背景 当前社会各行业领域竞争压力非常大,随着当前时代的信息化,科学化发展,让社会各行业领域都争相使用新的信息技术,对行业内的各种相关数据进行科学化,规范化管理。这样的大环境让那些止步不前,…...
你需要了解的Android主题相关知识
在 Android 开发中,主题(Theme)是用于定义应用的视觉风格的一组样式集合。主题决定了应用的配色、字体样式、控件外观等,是整个应用的一致性视觉体验的重要组成部分。以下是对 Android 主题的全面介绍,包括主题的基础概…...
基于Multisim数控直流稳压电源电路(含仿真和报告)
【全套资料.zip】数控直流稳压电源电路设计Multisim仿真设计数字电子技术 文章目录 功能一、Multisim仿真源文件二、原理文档报告资料下载【Multisim仿真报告讲解视频.zip】 功能 1.输出直流电压调节范围5-12V。 2.输出电流0-500mA。 3.输出直流电压能步进调节,步…...
精读预告Bigtable
文章目录 1. 引言:2. 背景 1. 引言: 在本期的精读会中,我们将深入解读另一篇具有里程碑意义的论文——《Bigtable: A Distributed Storage System for Structured Data》。这篇论文详细介绍了 Bigtable 作为谷歌用于管理结构化数据的分布式存…...
软件架构演变:从单体架构到LLM链式调用
0 前言 软件架构——我们数字世界的蓝图——自20世纪中叶计算机时代诞生以来,已经发生了巨大演变。 20世纪60年代和70年代早期,以大型主机和单体软件为主导。而今天,数字领域已完全不同,运行在由云计算、API连接、AI算法、微服务…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
相机从app启动流程
一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
SpringTask-03.入门案例
一.入门案例 启动类: package com.sky;import lombok.extern.slf4j.Slf4j; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cache.annotation.EnableCach…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
