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

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);
            }
        }
    };

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值