参考 http://blog.csdn.net/ryfdizuo/article/details/7916996
缓存的数据结构采用哈希表,key到value的映射。
网上有些资料采用记录数据的使用时刻 实现LRU策略,此处采用双向链表 实现LRU策略。LRU Least Recently Used,MRU Most Recently Used
双向链表,lruPtr头指向最近最少使用的元素,mruPtr头指向最近最多使用的元素。
LRUCache<int, int> tc(3); //最大三个元素
tc.insert(1, 101);
tc.insert(2, 102);
tc.insert(3, 103);
最终存储结构如下图:
哈希表中的元素:
- 黄色是 key域,哈希的键
- 蓝色是value域,存储的数据值
- 红色是newerPtr 域,指向下一个更新的 哈希项
- 绿色是oldPtr域,指向前一个更旧的 哈希项
LRUCache缓存中 保存mruPtr和lruPtr,缓存的查找、更新元素 首先从hash_table中发起,然后同步更新到双向链表中。
lru.hpp
- /*
- * Implementation of an LRU cache with a maximum size.
- *
- * See http://code.google.com/p/lru-cache-cpp/ for usage and limitations.
- *
- * Licensed under the GNU LGPL: http://www.gnu.org/copyleft/lesser.html
- *
- * Pierre-Luc Brunelle, 2011
- * pierre-luc.brunelle@polytml.ca
- *
- * 使用stl中的map替换hash_table
- * Peteryfren China, 2012
- */
- #include <map>
- #include <sstream>
- #include <cassert>
- namespace lru{
- //-------------------------------------------------------------
- // Bucket
- //-------------------------------------------------------------
- template<class K, class V>
- struct LRUCacheH4Value
- {
- typedef std::pair<const K, LRUCacheH4Value<K, V> > Val;
- LRUCacheH4Value()
- : _v(), _older(NULL), _newer(NULL) { }
- LRUCacheH4Value(const V & v, Val * older, Val * newer)
- : _v(v), _older(older), _newer(newer) { }
- V _v;
- Val * _older;
- Val * _newer;
- };
- //-------------------------------------------------------------
- // Const Iterator
- //-------------------------------------------------------------
- template<class K, class V>
- class LRUCacheH4ConstIterator
- {
- public:
- typedef std::pair<const K, LRUCacheH4Value<K, V> > Val;
- typedef LRUCacheH4ConstIterator<K, V> const_iterator;
- typedef Val & reference;
- typedef Val * pointer;
- enum DIRECTION {
- MRU_TO_LRU = 0,
- LRU_TO_MRU
- };
- LRUCacheH4ConstIterator(const Val * ptr = NULL, DIRECTION dir = MRU_TO_LRU);
- const_iterator & operator++();
- const_iterator operator++(int);
- bool operator==(const const_iterator & other);
- bool operator!=(const const_iterator & other);
- const K & key() const;
- const V & value() const;
- private:
- const Val * _ptr;
- DIRECTION _dir;
- };
- template<class K, class V>
- LRUCacheH4ConstIterator<K, V>::LRUCacheH4ConstIterator(
- const typename LRUCacheH4ConstIterator<K, V>::Val * ptr,
- typename LRUCacheH4ConstIterator<K, V>::DIRECTION dir)
- : _ptr(ptr), _dir(dir)
- {
- }
- template<class K, class V>
- LRUCacheH4ConstIterator<K, V> & LRUCacheH4ConstIterator<K, V>::operator++()
- {
- assert(_ptr);
- _ptr = (_dir == LRUCacheH4ConstIterator<K, V>::MRU_TO_LRU ? _ptr->second._older : _ptr->second._newer);
- return *this;
- }
- template<class K, class V>
- LRUCacheH4ConstIterator<K, V> LRUCacheH4ConstIterator<K, V>::operator++(int)
- {
- const_iterator ret = *this;
- ++*this;
- return ret;
- }
- template<class K, class V>
- bool LRUCacheH4ConstIterator<K, V>::operator==(const const_iterator & other)
- {
- return _ptr == other._ptr;
- }
- template<class K, class V>
- bool LRUCacheH4ConstIterator<K, V>::operator!=(const const_iterator & other)
- {
- return _ptr != other._ptr;
- }
- template<class K, class V>
- const K & LRUCacheH4ConstIterator<K, V>::key() const
- {
- assert(_ptr);
- return _ptr->first;
- }
- template<class K, class V>
- const V & LRUCacheH4ConstIterator<K, V>::value() const
- {
- assert(_ptr);
- return _ptr->second._v;
- }
- } // file scope
- namespace lru {
- //-------------------------------------------------------------
- // LRU Cache
- //-------------------------------------------------------------
- template<class K, class V>
- class LRUCacheH4
- {
- public:
- typedef LRUCacheH4ConstIterator<K, V> const_iterator;
- public:
- LRUCacheH4(int maxsize); // Pre-condition: maxsize >= 1
- LRUCacheH4(const LRUCacheH4 & other);
- ~LRUCacheH4() { _map.clear(); }
- V & operator[](const K & key);
- void insert(const K & key, const V & value);
- int size() const;
- int maxsize() const;
- bool empty() const;
- const_iterator find(const K & key); // updates the MRU
- const_iterator find(const K & key) const; // does not update the MRU
- const_iterator mru_begin() const; // from MRU to LRU
- const_iterator lru_begin() const; // from LRU to MRU
- const_iterator end() const;
- void dump_mru_to_lru(std::ostream & os) const;
- private:
- typedef std::pair<const K, LRUCacheH4Value<K, V> > Val;
- typedef std::map<K, LRUCacheH4Value<K,V> > MAP_TYPE;
- private:
- Val * _update_or_insert(const K & key);
- Val * _update(typename MAP_TYPE::iterator it);
- Val * _insert(const K & key);
- private:
- MAP_TYPE _map;
- Val * _mru;
- Val * _lru;
- int _maxsize;
- };
- // Reserve enough space to avoid resizing later on and thus invalidate iterators
- template<class K, class V>
- LRUCacheH4<K, V>::LRUCacheH4(int maxsize)
- : _mru(NULL),
- _lru(NULL),
- _maxsize(maxsize)
- {
- if (_maxsize <= 0)
- throw "LRUCacheH4: expecting cache size >= 1";
- }
- template<class K, class V>
- LRUCacheH4<K, V>::LRUCacheH4(const LRUCacheH4<K, V> & other)
- : _maxsize(other._maxsize),
- _mru(NULL),
- _lru(NULL)
- {
- for (const_iterator it = other.lru_begin(); it != other.end(); ++it)
- this->insert(it.key(), it.value());
- }
- template<class K, class V>
- V & LRUCacheH4<K, V>::operator[](const K & key)
- {
- return _update_or_insert(key)->second._v;
- }
- template<class K, class V>
- void LRUCacheH4<K, V>::insert(const K & key, const V & value)
- {
- _update_or_insert(key)->second._v = value;
- }
- template<class K, class V>
- int LRUCacheH4<K, V>::size() const
- {
- return _map.size();
- }
- template<class K, class V>
- int LRUCacheH4<K, V>::maxsize() const
- {
- return _maxsize;
- }
- template<class K, class V>
- bool LRUCacheH4<K, V>::empty() const
- {
- return size() > 0;
- }
- // updates MRU
- template<class K, class V>
- typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::find(const K & key)
- {
- typename MAP_TYPE::iterator it = _map.find(key);
- if (it != _map.end())
- return const_iterator(_update(it), const_iterator::MRU_TO_LRU);
- else
- return end();
- }
- // does not update MRU
- template<class K, class V>
- typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::find(const K & key) const
- {
- typename MAP_TYPE::iterator it = _map.find(key);
- if (it != _map.end())
- return const_iterator(&*it, const_iterator::MRU_TO_LRU);
- else
- return end();
- }
- template<class K, class V>
- void LRUCacheH4<K, V>::dump_mru_to_lru(std::ostream & os) const
- {
- os << "LRUCacheH4(" << size() << "/" << maxsize() << "): MRU --> LRU: " << std::endl;
- for (const_iterator it = mru_begin(); it != end(); ++it)
- os << it.key() << ": " << it.value() << std::endl;
- }
- template<class K, class V>
- typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::mru_begin() const
- {
- return const_iterator(_mru, const_iterator::MRU_TO_LRU);
- }
- template<class K, class V>
- typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::lru_begin() const
- {
- return const_iterator(_lru, const_iterator::LRU_TO_MRU);
- }
- template<class K, class V>
- typename LRUCacheH4<K, V>::const_iterator LRUCacheH4<K, V>::end() const
- {
- return const_iterator();
- }
- template<class K, class V>
- typename LRUCacheH4<K, V>::Val * LRUCacheH4<K, V>::_update_or_insert(const K & key)
- {
- typename MAP_TYPE::iterator it = _map.find(key);
- if (it != _map.end())
- return _update(it);
- else
- return _insert(key);
- }
- template<class K, class V>
- typename LRUCacheH4<K, V>::Val * LRUCacheH4<K, V>::_update(typename MAP_TYPE::iterator it)
- {
- LRUCacheH4Value<K, V> & v = it->second;
- Val * older = v._older;
- Val * newer = v._newer;
- Val * moved = &*it;
- // possibly update the LRU
- if (moved == _lru && _lru->second._newer)
- _lru = _lru->second._newer;
- if (moved != _mru) {
- // "remove" key from current position
- if (older)
- older->second._newer = newer;
- if (newer)
- newer->second._older = older;
- // "insert" key to MRU position
- v._older = _mru;
- v._newer = NULL;
- _mru->second._newer = moved;
- _mru = moved;
- }
- return moved;
- }
- template<class K, class V>
- typename LRUCacheH4<K, V>::Val * LRUCacheH4<K, V>::_insert(const K & key)
- {
- // if we have grown too large, remove LRU
- if (_map.size() >= _maxsize) {
- Val * old_lru = _lru;
- if (_lru->second._newer) {
- _lru = _lru->second._newer;
- _lru->second._older = NULL;
- }
- _map.erase(old_lru->first);
- }
- // insert key to MRU position
- std::pair<typename MAP_TYPE::iterator, bool> ret
- = _map.insert( Val(key, LRUCacheH4Value<K, V>(V(), _mru, NULL)) );
- Val * inserted = &*ret.first;
- if (_mru)
- _mru->second._newer = inserted;
- _mru = inserted;
- // possibly update the LRU
- if (!_lru)
- _lru = _mru;
- else if (!_lru->second._newer)
- _lru->second._newer = _mru;
- return inserted;
- }
- } // namespace lru
测试代码:
- #include <iostream>
- #include "lru.hpp"
- using namespace lru;
- using namespace std;
- int main()
- {
- typedef LRUCacheH4<int, int> CacheType;
- CacheType tc(3);
- tc.insert(1, 101);
- tc.insert(2, 102);
- tc.insert(3, 103);
- tc.insert(2, 1002);
- cout << tc[1] << endl;
- cout << "================" << endl;
- for (CacheType::const_iterator it = tc.mru_begin(); it != tc.end(); ++it)
- cout << it.key() << " " << it.value() << endl;
- cout << "================" << endl;
- for (CacheType::const_iterator it = tc.lru_begin(); it != tc.end(); ++it)
- cout << it.key() << " " << it.value() << endl;
- system("PAUSE");
- return 0;
- }
参考:
相关推荐
项目参考了LevelDB的LRU缓存设计,并在此基础上进行了优化,采用了数组形式存储元信息,并尝试实现无锁化技术,以提升系统性能。 ## 项目的主要特性和功能 1. 多线程支持系统能够支持多线程并发读写操作,确保在高...
LRU(Least Recently Used)缓存策略是一种常用的内存管理策略,它通过淘汰最近最少使用的数据来保持缓存容量。在Go语言中,有许多库...同时,学习和研究开源的LRU缓存库也有助于提升我们的Go编程技巧和系统设计能力。
“Python—LRU缓存.zip”是一个压缩文件,其中包含了使用Python实现的最近最少使用...缓存系统设计者:LRU缓存算法在缓存系统设计中有着广泛的应用,这个资源可以为缓存系统设计者提供实现和优化缓存策略的思路。
如果这个LRU缓存设计为多线程安全,那么需要考虑同步控制。可以使用`synchronized`关键字或者`java.util.concurrent`包中的工具,如`ConcurrentHashMap`来实现线程安全的缓存操作。 6. **性能优化**: - 使用`...
在Java中实现LRU缓存机制,不仅可以帮助我们更好地理解和应用数据结构,还能在实际开发中提高程序的性能。本文将详细介绍如何在Java中实现LRU缓存机制,包括其原理、实现方式以及编码实践。 LRU缓存机制是一种非常...
在JavaScript开发中,LRU缓存可以帮助优化性能,尤其是在处理大量数据时,通过保留最近最常使用的数据而舍弃不常用的数据。 标题中的"quicklru简单的最近最少使用LRU缓存"指的是一种轻量级的LRU实现,旨在提供高效...
1. LRU缓存类的设计和实现,包括如何使用哈希表和链表组合实现数据结构。 2. 插入、删除、查找和更新操作的逻辑,特别是如何在数据访问后更新数据的使用顺序。 3. 淘汰策略的实现,即如何确定并移除最近最少使用的...
LRU(Least Recently Used)缓存是一种常用的内存管理策略,用于在有限的内存空间中...通过对这些代码的学习和理解,开发者可以掌握如何设计和实现自己的LRU缓存系统,从而在实际项目中应用这一高效的内存管理策略。
LRU缓存是一种常见的缓存淘汰策略,全称为“最近最少使用”。它的核心思想是,当缓存空间有限,无法存放所有数据时,优先淘汰最近最少使用的数据。LRU策略在许多系统中都有应用,特别是在数据库系统、操作系统以及...
设计LRU(最近最少使用)缓存结构,该结构在构造时确定大小,假设大小为 capacity ,操作次数是 n ,并有如下功能: 1. Solution(int capacity) 以正整数作为容量 capacity 初始化 LRU 缓存 2. get(key):如果关键字 ...
C语言实现LRU缓存涉及到数据结构的设计、哈希表和链表的应用,以及高效的内存管理。以下是对这个主题的详细讲解: 1. **LRU算法原理**: LRU算法基于“最近使用频率越高,将来越可能再次被使用”的假设。在缓存中...
**Swift-SPTPersistentCache:一个高效且灵活的LRU缓存管理框架** 在iOS和macOS应用开发中,缓存管理是性能优化的关键部分。它能够帮助减少网络请求,提高用户体验,尤其是在处理大量数据或者频繁访问同一资源时。`...
Java 中实现 LRU 缓存有多种方法,包括使用 LinkedHashMap 和自己设计数据结构。使用 LinkedHashMap 实现 LRU 缓存是最简单的方法,因为 LinkedHashMap 自身已经实现了顺序存储,默认情况下是按照元素的添加顺序存储...
"链表数据结构与LRU缓存淘汰算法" 链表是一种基础的数据结构,它广泛应用于软件开发和硬件设计中。今天我们将讨论如何使用链表来实现LRU缓存淘汰算法。 首先,让我们来讨论缓存的概念。缓存是一种提高数据读取性能...
在Python版本的LRU缓存实现中,类`LRUCache`包括以下关键部分: 1. 初始化方法`__init__`: 接收一个参数`capacity`,表示缓存的最大容量。创建一个字典`cache`用于存储键值对,一个列表`keys`用于存储键的顺序,...
LeetCode第146题名为"LRU缓存",其核心任务是设计一个数据结构,该数据结构支持以下操作: 1. `put(key, value)`:如果`key`不存在,则插入键值对;如果`key`已经存在,则更新其对应的`value`。 2. `get(key)`:...
在Java编程中,实现LRU缓存通常涉及数据结构的设计,如使用HashMap和LinkedList。下面将详细探讨第146题LRU缓存的解题思路、实现方法以及相关的Java知识。 首先,我们要理解LRU缓存的工作原理。当新数据进入缓存时...
146_LRU缓存.py
总的来说,LRU缓存策略是优化性能的有效工具,通过合理设计的数据结构和算法,我们可以用JavaScript轻松实现。LeetCode上的这道题就是很好的实践机会,帮助开发者深入理解LRU机制及其在实际问题中的应用。通过解析...