C++学习(四六九)LRU Least Recently Used算法

2023-11-17

LRU是Least Recently Used的缩写,即最近最少使用(最近一段时间最少使用),是一种常用的页面置换算法,选择最近最久未使用的页面予以淘汰。该算法赋予每个页面一个访问字段,用来记录一个页面自上次被访问以来所经历的时间 t,当须淘汰一个页面时,选择现有页面中其 t 值最大的,即最近最少使用的页面予以淘汰。

最近不是空间的概念,是时间概念,即最近一段时间。

1、最开始时,内存空间是空的,因此依次进入A、B、C是没有问题的
2、当加入D时,就出现了问题,内存空间不够了,因此根据LRU算法,内存空间中A待的时间最为久远,选择A,将其淘汰
3、当再次引用B时,内存空间中的B又处于活跃状态,而C则变成了内存空间中,近段时间最久未使用的
4、当再次向内存空间加入E时,这时内存空间又不足了,选择在内存空间中待的最久的C将其淘汰出内存,这时的内存空间存放的对象就是E->B->D

算法实现:

LRUCache通过一个list列表和一个map表实现读写功能,list表存放key,map表存放key、value、list表对应的位置信息,list表负责构造最近最少使用列表,新增加或新使用的元素放在列表最后,map表负责快速查找。

/**
     * Least-recently-used cache class.
     * K = key type, T = value type
     *
     * usage:
     *    LRUCache<K,T> cache;
     *    cache.put( key, value );
     *    LRUCache.Record rec = cache.get( key );
     *    if ( rec.valid() )
     *        const T& value = rec.value();
     */
    template<typename K, typename T, typename COMPARE=std::less<K> >
    class LRUCache
    {
    public:
        struct Record {
            Record() : _valid(false) { }
            Record(const T& value) : _value(value), _valid(true) { }
            bool valid() const { return _valid; }
            const T& value() const { return _value; }
        private:
            bool _valid;
            T    _value;
            friend class LRUCache;
        };

        struct Functor {
            virtual void operator()(const K& key, const T& value) =0;
        };

    protected:
        typedef typename std::list<K>::iterator      lru_iter;
        typedef typename std::list<K>                lru_type;
        typedef typename std::pair<T, lru_iter>      map_value_type;
        typedef typename std::map<K, map_value_type> map_type;
        typedef typename map_type::iterator          map_iter;
        typedef typename map_type::const_iterator    map_const_iter;

        map_type _map;
        lru_type _lru;
        unsigned _max;
        unsigned _buf;
        unsigned _queries;
        unsigned _hits;
        bool     _threadsafe;
        mutable Threading::Mutex _mutex;

    public:
        LRUCache( unsigned max =100 ) : _max(max), _threadsafe(false) {
            _queries = 0;
            _hits = 0;
            setMaxSize_impl(max);
        }
        LRUCache( bool threadsafe, unsigned max =100 ) : _max(max), _threadsafe(threadsafe) {
            _queries = 0;
            _hits = 0;
            setMaxSize_impl(max);
        }

        /** dtor */
        virtual ~LRUCache() { }

        void insert( const K& key, const T& value ) {
            if ( _threadsafe ) {
                Threading::ScopedMutexLock lock(_mutex);
                insert_impl( key, value );
            }
            else {
                insert_impl( key, value );
            }
        }

        bool get( const K& key, Record& out ) {
            if ( _threadsafe ) {
                Threading::ScopedMutexLock lock(_mutex);
                get_impl( key, out );
            }
            else {
                get_impl( key, out );
            }
            return out.valid();
        }

        bool has( const K& key ) {
            if ( _threadsafe ) {
                Threading::ScopedMutexLock lock(_mutex);
                return has_impl( key );
            }
            else {
                return has_impl( key );
            }
        }

        void erase( const K& key ) {
            if ( _threadsafe ) {
                Threading::ScopedMutexLock lock(_mutex);
                erase_impl( key );
            }
            else {
                erase_impl( key );
            }
        }

        void clear() {
            if ( _threadsafe ) {
                Threading::ScopedMutexLock lock(_mutex);
                clear_impl();
            }
            else {
                clear_impl();
            }
        }

        void setMaxSize( unsigned max ) {
            if ( _threadsafe ) {
                Threading::ScopedMutexLock lock(_mutex);
                setMaxSize_impl( max );
            }
            else {
                setMaxSize_impl( max );
            }
        }

        unsigned getMaxSize() const {
            return _max;
        }

        CacheStats getStats() const {
            return CacheStats(
                _map.size(), _max, _queries, _queries > 0 ? (float)_hits/(float)_queries : 0.0f );
        }

        void iterate(Functor& functor) const {
            if (_threadsafe) {
                Threading::ScopedMutexLock lock(_mutex);
                iterate_impl(functor);
            }
            else {
                iterate_impl(functor);
            }
        }

    private:

        void insert_impl( const K& key, const T& value ) {
            map_iter mi = _map.find( key );
            if ( mi != _map.end() ) {
                _lru.erase( mi->second.second );
                mi->second.first = value;
                _lru.push_back( key );
                mi->second.second = _lru.end();
                mi->second.second--;
            }
            else {
                _lru.push_back( key );
                lru_iter last = _lru.end(); last--;
                _map[key] = std::make_pair(value, last);
            }

            if ( _map.size() > _max ) {
                for( unsigned i=0; i < _buf; ++i ) {
                    const K& key = _lru.front();
                    _map.erase( key );
                    _lru.pop_front();
                }
            }
        }

        void get_impl( const K& key, Record& result ) {
            _queries++;
            map_iter mi = _map.find( key );
            if ( mi != _map.end() ) {
                _lru.erase( mi->second.second );
                _lru.push_back( key );
                lru_iter new_iter = _lru.end(); new_iter--;
                mi->second.second = new_iter;
                _hits++;
                result._value = mi->second.first;
                result._valid = true;
            }
        }

        bool has_impl( const K& key ) {
            return _map.find( key ) != _map.end();
        }

        void erase_impl( const K& key ) {
            map_iter mi = _map.find( key );
            if ( mi != _map.end() ) {
                _lru.erase( mi->second.second );
                _map.erase( mi );
            }
        }

        void clear_impl() {
            _lru.clear();
            _map.clear();
            _queries = 0;
            _hits = 0;
        }

        void setMaxSize_impl( unsigned max ) {
            _max = std::max(max,10u);
            _buf = _max/10u;
            while( _map.size() > _max ) {
                const K& key = _lru.front();
                _map.erase( key );
                _lru.pop_front();
            }
        }

        void iterate_impl(Functor& f) const {
            for (map_const_iter i = _map.begin(); i != _map.end(); ++i) {
                f(i->first, i->second.first);
            }
        }
    };

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

C++学习(四六九)LRU Least Recently Used算法 的相关文章

随机推荐

  • java:hashMap: get(null)引发的对其数据结构具体形态的思考

    ref 原文 https blog csdn net fenglongmiao article details 79656198 note 我们知道HashMap集合是允许存放null值的 hashMap是根据key的hashCode来寻找
  • 软工导论知识框架(五)面向对象方法学

    传统软件工程方法学适用于中小型软件产品开发 面向对象软件工程方法学适用于大型软件产品开发 一 四要素 对象 类 继承 传递消息实现通信 二 概念 1 对象 具有相同状态的一组操作的集合 对状态和操作的封装 2 类 对具有相同状态和相同操作的
  • 带你手写基于 Spring 的可插拔式 RPC 框架(三)通信协议模块

    在写代码之前我们先要想清楚几个问题 我们的框架到底要实现什么功能 我们要实现一个远程调用的 RPC 协议 最终实现效果是什么样的 我们能像调用本地服务一样调用远程的服务 怎样实现上面的效果 前面几章已经给大家说了 使用动态代理 在客户端生成
  • CentOS7中安装mysql

    1 确保本机的mysql已经卸载干净 需要将mariadb和mysql全部卸载 rpm qa grep i mariadb rpm qa grep i mysql 使用rpm ev nodeps 命令将查询出来的文件逐一卸载 sudo rp
  • Docker Compose、Docker Swarm (docker进阶 狂神)

    文章目录 Docker Compose 安装 开源项目 博客 实战 自己编写微服务上线 Docker Swarm 四台机器安装docker环境 Swarm集群搭建 Raft协议 体会 灰度发布 金丝雀发布 其他命令学习方式 Docker C
  • notepad++以16进制查看文件

    1 Notepad 可以编辑PE文件 二进制文件即HEX码 2进制 16进制都可以 通过附加的组件HexEditor即可实现 另外一款Notepad 自带插件TextFX也有这个功能 但实现效果不如Hex Editor 下载地址 https
  • CH1-绪论

    文章目录 算法时间复杂度的计算 一 冒泡排序简介 从小到大排序 算法时间复杂度的计算 我们一般只关心随着问题规模n趋于无穷时 函数中对函数结果影响最大的项 比如说 T n 3n 3 当n非常大的时候 常数3和n的系数3对函数结果的影响就很小
  • vue--综合组件间的通信

    二 综合组件之间的通信 实现一个ToDoList 完成所有的组件的创建和使用 add点击add按钮时候 将用户输入的内容 todoinput 显示在 todolist 核心代码 兄弟组件间通信 步骤1 var bus new Vue 步骤2
  • QT210烧写UBOOT到SD卡原理以及UBOOT启动

    原文地址 http blog csdn net shushi0123 article details 8018998 世界早已进入cortex a8了 我也得跟进一下所以买了QT210的开发板 长话短说开始搞SD卡烧写UBOOT 从SD启动
  • TCP选项之SO_LINGER

    SO LINGER这个选项在我以前带队改造haproxy的时候引出过一个reset RST 客户端连接的bug SO LINGER作用 设置函数close 关闭TCP连接时的行为 缺省close 的行为是 如果有数据残留在socket发送缓
  • 手动实现 call、apply、bind

    手动实现 call apply bind 改变 this的指向 就是将函数fn放入传入的context中 然后执行context fn 此时的fn中的this就变成了context 在函数执行完毕之后 需删除context中的fn call
  • 腾讯云2核4G服务器性能如何?能安装几个网站?

    腾讯云2核4G服务器能安装多少个网站 2核4g配置能承载多少个网站 一台2核4G服务器可以安装多少个网站 阿腾云2核4G5M带宽服务器目前安装了14个网站 从技术角度是没有限制的 只要云服务器性能够用 想安装几个网站就安装几个网站 但是从公
  • Windows系统下安装Ubuntu子系统

    总共分三步 1 网上是有Windows 10版本的安装教程 链接如下 14条消息 Windows系统中安装ubutu子系统 惜洛 Jankin的博客 CSDN博客 2 补充Windows 11版本的安装 大同小异 3 如果出现报错 14条消
  • linux非阻塞socket教程

    本文并非解释什么是非阻塞socket 也不是介绍socket API的用法 取而代替的是让你感受实际工作中的代码编写 虽然很简陋 但你可以通过man手册与其它资源非富你的代码 请注意本教程所说的主题 如果细说 内容可以达到一本书内容 你会发
  • csgo 直连服务器,csgo你只可以从大厅连接此服务器解决办法

    csgo你只可以从大厅连接此服务器解决办法 请完成以下步骤刷新您的 Steam 设置 您注销并完全退出 Steam 请打开 Internet Explore Safari 或 Firefox 和并在网址列中输入 Steam flushcon
  • 高斯模糊处理

    借鉴 http blog sina com cn s blog 861912cd0101957x html http www ruanyifeng com blog 2012 11 gaussian blur html 二维高斯曲面的公式
  • input js number 整数_JS通过正则限制 input 输入框只能输入整数、小数(金额或者现金) 两位小数...

    第一 限制只能是整数 如果不是整数就直接alert 第二 限制是两位的小数 原理 通过 正则表达式判断 不满足 执行alert 第一个正则表达式是 d 表示可以是一个或者多个数字 第二个正则表达式是 d d 0 2 表示必须是数字开头 数字
  • 别踩雷了!交互设计必须遵守这10大规范!

    UI 设计师需要理解交互设计 因为不懂交互的 UI 设计师不能成为优秀的 UI 设计师 交互设计涉及用户与产品及其使用的服务之间的关系 而 UI 设计不仅仅是将功能需求可视化 还需要创造卓越的用户体验 因此 大多数 UI 设计师需要了解交互
  • 第二十一节:JS中的继承

    上节回顾 1 所有 函数 都有一个特殊属性 prototype prototype指向一个对象 称之为原型对象 原型对象上只有一个属性 constructor constructor又指向了构造函数 形成了一个闭环 2 所有 对象 都有一个
  • C++学习(四六九)LRU Least Recently Used算法

    LRU是Least Recently Used的缩写 即最近最少使用 最近一段时间最少使用 是一种常用的页面置换算法 选择最近最久未使用的页面予以淘汰 该算法赋予每个页面一个访问字段 用来记录一个页面自上次被访问以来所经历的时间 t 当须淘