当前位置: 首页 > news >正文

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.dtcms.com/a/328126.html

相关文章:

  • 农业智慧大屏系统 - Flask + Vue实现
  • 云计算分类与主流产品
  • iOS 文件管理全流程实战,从开发调试到数据迁移
  • 初识神经网络04——构建神经网络2
  • 软路由雷达:基于OpenWrt系统的传统逆向思路的冷门实现
  • 外部中断寄存器的实现-库函数版(STC8)
  • Android性能优化:架构层面的性能考量
  • 【第13话:泊车感知】场景检测与分割:自主泊车场景中的检测及语义分割方法
  • Linux中的tar 和crontab命令
  • 需求的透明化如何实现
  • Threejs 设置灯光照射点位置 辅助器不跟随移动
  • 基于MATLAB实现的PSO优化BP神经网络
  • Java数据结构之数组
  • 电商双 11 美妆数据分析学习报告
  • 锅气:「现炒之魂·烟火人间」
  • 【Unity】Unity中ContentSizeFitter有时无法及时自适应大小问题解决
  • Flutter 基于google验证登录实现
  • HeidiSQL 连接 MySQL 报错 10061
  • Xshell连接虚拟机密码错误解决方法
  • Ansible部署应用
  • Gradle 配置教程:与 Maven 对比详解(含完整迁移指南)
  • methods和computed的区别
  • tlias智能学习辅助系统--Maven高级-继承
  • 北京JAVA基础面试30天打卡08
  • C++动态代理技术详解:实现原理与应用场景
  • Java静态代理和动态代理
  • Linux驱动开发probe字符设备的完整创建流程
  • 【游戏优化笔记】开发中如何减少建筑和树木等环境元素的资源消耗?
  • 【RHCE】自动化备份全网服务器数据平台
  • 36-综合案例开发-2