LRU算法与LFU算法

知识点:

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

 

LRU本质就是一个页面置换算法,关键就是如何实现get()和put()函数O(1)时间复杂度

具体内容请打开leedcode上面这题:

146. LRU 缓存 - 力扣(LeetCode)

如何实现O(1),关键在于链表和哈希的使用,我来结合代码讲解:

//首先,定义一个capacity、list和unordered_map成员变量,注意的是_hashmp存放的第二个参数为list迭代器,list存放的是pair类型,first为key,second为value
//其次:实现put函数,如果存在,我们只需要更新器内容,并放在链表的头部(注:尾部是不使用的),但当我们put的是不存在的,需要判断容量是否满足,是否需要删除list尾部,然后再插入到链表的头部,更新——_hashmp注意放的是iterator
//最后,实现get函数,不存在返回-1,否则,找到该value,然后将其提前保存放入list头部,再将其原位置删除,同时更新hash中迭代器位置
class LRUCache {
public:LRUCache(int capacity) {_capacity = capacity;}//O(1):int get(int key) {//通过key得到value,否则返回-1//去哈希中查找auto hashit = _hashmap.find(key);if(hashit == _hashmap.end()){//未找到return -1;}else{//找到auto listit = hashit->second;//更新该节点的使用情况pair<int,int> kv = *listit;_list.erase(listit);_list.push_front(kv);//更新哈希_hashmap[key] = _list.begin();return kv.second;}}//O(1):void put(int key, int value) {//存在更新,不存在插入//判断是否存在auto hashit = _hashmap.find(key);//注意:hashit是迭代器if(hashit == _hashmap.end()){//不存在,插入,注意capacityif(_list.size() == _capacity){//删除最近未使用的_hashmap.erase(_list.back().first);_list.pop_back();}//插入到链表头部+更新哈希_list.push_front(make_pair(key,value));_hashmap[key] = _list.begin();}else{//存在,更新数据并且放在链表头部,我们尾部是最近未使用数据//获取list中迭代器位置auto listit = hashit->second;//更新KVpair<int,int> kv = *listit;kv.second = value;//将链表中该节点位置放入头部_list.erase(listit);_list.push_front(kv);//更新哈希_hashmap[key] = _list.begin();}}
private:int _capacity;//容量list<pair<int,int>> _list;unordered_map<int,list<pair<int,int>>::iterator> _hashmap;
};

LRU面试不算经常考察的内容,但是也需要我们会实现到O(1)的复杂度

补充:

现在还存在面试常考的另一种算法LFU算法

该算法是通过一个count记录来处理最少使用的情况,下面联系leedcode例题来讲解:

460. LFU 缓存 - 力扣(LeetCode)

实现过程:

class LFUCache {
public:LFUCache(int capacity) {_capacity = capacity;}int get(int key) {auto hashit = _hashmp.find(key);if (hashit == _hashmp.end()) return -1;// 获取当前节点并更新频率auto listit = hashit->second;auto kcv = *listit;_list.erase(listit);  // 先移除旧节点// 更新频率并重新插入到正确位置kcv.second.first++;auto new_it = insertIntoSortedList(kcv);_hashmp[key] = new_it;return kcv.second.second;}void put(int key, int value) {auto hashit = _hashmp.find(key);if (hashit == _hashmp.end()) {// 缓存已满,淘汰频率最低且最久未使用的节点if (_list.size() >= _capacity) {_hashmp.erase(_list.back().first);_list.pop_back();}// 插入新节点(频率=1)auto kcv = make_pair(key, make_pair(1, value));auto new_it = insertIntoSortedList(kcv);_hashmp[key] = new_it;} else {// 更新现有节点(逻辑同get)auto listit = hashit->second;auto kcv = *listit;_list.erase(listit);kcv.second.first++;kcv.second.second = value;  // 更新valueauto new_it = insertIntoSortedList(kcv);_hashmp[key] = new_it;}}private:// 辅助函数:将节点按频率和访问顺序插入到链表list<pair<int, pair<int, int>>>::iterator insertIntoSortedList(const pair<int, pair<int, int>>& kcv) {// 遍历链表,找到第一个频率 <= 当前节点频率的位置for (auto it = _list.begin(); it != _list.end(); ++it) {if (it->second.first <= kcv.second.first) {return _list.insert(it, kcv);  // 插入到该位置前}}// 如果所有节点频率都更低,插入到末尾return _list.insert(_list.end(), kcv);}int _capacity;list<pair<int, pair<int, int>>> _list;  // (key, (count, value))unordered_map<int, list<pair<int, pair<int, int>>>::iterator> _hashmp;
};

通过list和unordered_map来实现,但是需要两个pair(重点),另外就是就是insert和erase操作使用,希望对大家有帮助!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/93064.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/93064.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

目标检测公开数据集全解析:从经典到前沿

目标检测公开数据集全解析&#xff1a;从经典到前沿 一、引言 目标检测&#xff08;Object Detection&#xff09;是计算机视觉领域的核心任务之一&#xff0c;旨在在图像或视频中识别并定位感兴趣的物体。与图像分类不同&#xff0c;目标检测不仅需要判断物体的类别&#xf…

数据备份与进程管理

一、数据备份1.Linux服务器中需要备份的数据&#xff08;1&#xff09;Linux系统重要数据&#xff1a;/root/目录&#xff0c;/home/目录&#xff0c;/etc/目录&#xff08;2&#xff09;安装服务的数据&#xff1a;Apache&#xff08;配置文件&#xff0c;网页主目录&#xff…

docker volume卷入门教程

1. 基础概念 Docker卷是专门用于持久化容器数据的存储方案&#xff0c;独立于容器生命周期。其核心优势包括&#xff1a; 数据持久化&#xff1a;容器删除后数据仍保留跨容器共享&#xff1a;多个容器可访问同一卷备份与迁移&#xff1a;支持直接复制卷数据驱动支持&#xff1a…

计算机网络——协议

1. 计算机网络分层1.1 OSI 7层模型应用层表示层会话层传输层网络层数据链路层物理层1.2 TCP/IP 4 层模型应用层运输层网际层网络接口层1.3 5层体系机构应用层传输层网络层数据链路层物理层2. 应用层协议2.1 HTTP协议2.1.1 基本介绍HTTP&#xff08;HyperText Transfer Protocol…

【React】hooks 中的闭包陷阱

在 React Hooks 中的 闭包陷阱&#xff08;Closure Trap&#xff09;在 useEffect、事件回调、定时器等场景里很常见。1. 闭包陷阱是什么 当你在函数组件里定义一个回调&#xff08;比如事件处理函数&#xff09;&#xff0c;这个回调会捕获当时渲染时的变量值。如果后面状态更…

校园快递小程序(腾讯地图API、二维码识别、Echarts图形化分析)

&#x1f388;系统亮点&#xff1a;腾讯地图API、二维码识别、Echarts图形化分析&#xff1b;一.系统开发工具与环境搭建1.系统设计开发工具后端使用Java编程语言的Spring boot框架 项目架构&#xff1a;B/S架构 运行环境&#xff1a;win10/win11、jdk17小程序&#xff1a; 技术…

Python网络爬虫(二) - 解析静态网页

文章目录一、网页解析技术介绍二、Beautiful Soup库1. Beautiful Soup库介绍2. Beautiful Soup库几种解析器比较3. 安装Beautiful Soup库3.1 安装 Beautiful Soup 43.2 安装解析器4. Beautiful Soup使用步骤4.1 创建Beautiful Soup对象4.2 获取标签4.2.1 通过标签名获取4.2.2 通…

【Linux基础知识系列】第九十四篇 - 如何使用traceroute命令追踪路由

在网络环境中&#xff0c;了解数据包从源主机到目标主机的路径是非常重要的。这不仅可以帮助我们分析网络连接问题&#xff0c;还可以用于诊断网络延迟、丢包等问题。traceroute命令是一个强大的工具&#xff0c;它能够追踪数据包在网络中的路径&#xff0c;显示每一跳的延迟和…

达梦数据闪回查询-快速恢复表

Time:2025/08/12Author:skatexg一、环境说明DM数据库&#xff1a;DM8.0及以上版本二、适用场景研发在误操作或变更数据后&#xff0c;想马上恢复表到某个时间点&#xff0c;可以通过闪回查询功能快速实现&#xff08;通过全量备份恢复时间长&#xff0c;成本高&#xff09;三、…

力扣(LeetCode) ——225 用队列实现栈(C语言)

题目&#xff1a;用队列实现栈示例1&#xff1a; 输入&#xff1a; [“MyStack”, “push”, “push”, “top”, “pop”, “empty”] [[], [1], [2], [], [], []] 输出&#xff1a; [null, null, null, 2, 2, false] 解释&#xff1a; MyStack myStack new MyStack(); mySta…

微软推出AI恶意软件检测智能体 Project Ire

开篇 在8月5号&#xff0c;微软研究院发布了一篇博客文章&#xff0c;在该篇博客中推出了一款名为Project Ire的AI Agent。该Agent可以在无需人类协助的情况下&#xff0c;自主分析和分类二进制文件。它可以在无需了解二进制文件来源或用途的情况下&#xff0c;对文件进行完全的…

哪些对会交由SpringBoot容器管理?

在 Spring Boot 中,交由容器管理的对象通常称为“Spring Bean”,这些对象的创建、依赖注入、生命周期等由 Spring 容器统一管控。以下是常见的会被 Spring Boot 容器管理的对象类型及识别方式: 一、通过注解声明的组件(最常见) Spring Boot 通过类级别的注解自动扫描并注…

Android POS应用在android运行常见问题及解决方案

概述 本文档记录了在Android POS应用开发过程中遇到的两个关键问题及其解决方案&#xff1a; UnsatisfiedLinkError: couldnt find "libnative.so" 错误ActivityNotFoundException 错误商户信息一致性检查绕过 问题1&#xff1a;UnsatisfiedLinkError - libnative.so…

基于SpringBoot的旅游网站系统

1. 项目简介 旅游线路管理系统是一个基于Spring Boot的在线旅游服务平台&#xff0c;提供旅游线路展示、分类、预订、订单管理等功能。系统包含前台用户界面和后台管理模块&#xff0c;支持用户注册登录、线路浏览、收藏、下单支付、客服咨询等核心功能。管理员可管理线路信息、…

CVPR 2025 | 机器人操控 | RoboGround:用“掩码”中介表示,让机器人跨场景泛化更聪明

点击关注gongzhonghao【计算机sci论文精选】1.导读1.1论文基本信息论文标题&#xff1a;ROBOGROUND: Robotic Manipulation with Grounded Vision-Language Priors作者&#xff1a;Haifeng Huang, Xinyi Chen, Hao Li&#xff0c; Xiaoshen Han, Yilun Chen, Tai Wang, Zehan W…

构建Node.js单可执行应用(SEA)的方法

如果为了降低部署复杂度&#xff0c;可以考虑使用vercel/ncc。除非有特别理由&#xff0c;不建议使用SEA。1. 环境准备1.1. 基础要求Node.js: > 19.0.0 (推荐最新LTS版本)1.2. 安装依赖npm install postject typescript1.3. 验证环境node -v # 确认版本 > 19 ts…

Java19 Integer 位操作精解:compress与expand《Hacker‘s Delight》(第二版,7.4节)

compress(int i, int mask) 这个方法是Java 19中新增的一个强大的位操作函数。compress 方法的核心功能可以理解为 “按位过滤和压缩” 。过滤 (Filter): 它使用 mask&#xff08;掩码&#xff09;作为过滤器。对于输入整数 i&#xff0c;只有那些在 mask 中对应位为 1 的比特才…

minio部署和双机热备

安装单机版MinIO&#xff08;准备2台机器A、B,A、B服务器操作一致&#xff09;切换目录并下载MinIO二进制文件cd /usr/local/bin wget https://dl.minio.org.cn/server/minio/release/linux-amd64/minio chmod x minio编辑配置文件vi /etc/default/minio.confMINIO_VOLUMES&quo…

【Java】 Java 21 革命性升级:虚拟线程与结构化并发的深度实践指南

还在为高昂的AI开发成本发愁?这本书教你如何在个人电脑上引爆DeepSeek的澎湃算力! Java 21 作为 Oracle JDK 的长期支持版本,引入了多项革命性特性,其中虚拟线程(Virtual Threads)和结构化并发(Structured Concurrency)尤为突出。这些特性旨在解决传统线程模型在高并发…

Apache IoTDB 全场景部署:基于 Apache IoTDB 的跨「端-边-云」的时序数据库 DB+AI

Apache IoTDB 全场景部署&#xff1a;基于 Apache IoTDB 的跨「端-边-云」的时序数据库 DBAI 文章目录Apache IoTDB 全场景部署&#xff1a;基于 Apache IoTDB 的跨「端-边-云」的时序数据库 DBAIApache IoTDB 介绍Docker部署指导企业版数据库配套工具 WorkbenchTimechoDB&…