C++ 基于List与Map实现的LRU缓存

常见的缓存淘汰算法有先进先出淘汰算法(FIFO),最近最少使用淘汰算法(LSU),最近最久未使用算法(LRU),MRU(最近最常使用算法)。其中最常用的就是LRU缓存淘汰算法,下面给出代码实现。


#include "stdafx.h"
#include <iostream>
#include <map>
#include <list>
using namespace std;

template<typename TKey, typename TValue>
class SimpleLRUCache
{
private:
	int m_iMaxSize;
	list<TKey> m_listLru; // 保存Key的链表,维护访问顺序
	
	typedef pair<typename list<TKey>::iterator, TValue> MPair;
	typedef shared_ptr<MPair> PairPtr; //保证资源释放
	map<TKey, PairPtr> m_mapPair; // 保存Key在链表中的位置和Key对应的Value

public:
	SimpleLRUCache(int iMaxSize)
	{
		m_iMaxSize = iMaxSize;
	}

	bool Contain(TKey& szKey)
	{
		auto iterFind = m_mapPair.find(szKey);
		if (iterFind == m_mapPair.end())
			return false;
		return true;
	}

	bool Get(TKey& szKey, TValue &rValue)
	{
		auto iterFind = m_mapPair.find(szKey);
		if (iterFind == m_mapPair.end())
			return false;

		rValue = iterFind->second->second;

		//	访问后移至链表头部
		auto iterList = iterFind->second->first;
		m_listLru.erase(iterList);
		m_listLru.push_front(iterFind->first);
		iterFind->second->first = m_listLru.begin();

		return true;
	}

	bool Put(TKey& szKey, TValue& szValue)
	{
		if (Contain(szKey))
			return false;

		//	在链表的头部插入
		m_listLru.push_front(szKey);
		auto iterFront = m_listLru.begin();
		PairPtr pairPtr = make_shared<MPair>(iterFront, szValue);
		m_mapPair.insert(make_pair(szKey, pairPtr));

		//	判断缓存容量是否超过最大值
		if (m_listLru.size() > m_iMaxSize)
		{
			//	移除最久未被访问元素
			auto myKey = m_listLru.back();
			Remove(myKey);
		}

		return true;
	}

	bool Remove(TKey &szKey)
	{
		auto iterFind = m_mapPair.find(szKey);
		if (iterFind == m_mapPair.end())
			return false;
		auto iterList = iterFind->second->first;
		m_listLru.erase(iterList);
		m_mapPair.erase(iterFind);

		cout << "Remove key" << szKey << endl;

		return true;
	}
};


int main()
{
	SimpleLRUCache<int, int> lruCache(10);

	for (int i = 0; i < 13; i++)
	{
		lruCache.Put(i, i);
	}

	int iVal;
	bool bGet;
	for (int i = 12; i >=0; i--)
	{
		bGet = lruCache.Get(i, iVal);
		if (bGet)
		{
			cout << "Get key=" << i << ", val=" << iVal << endl;
		}
	}

    return 0;
}

核心设计思想:

1、使用链表维护访问顺序

2、使用map加速查找

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
LRU(Least Recently Used)是一种缓存淘汰策略,当缓存空间不足时,先淘汰最近最少使用的缓存块。在 C++ 中,可以使用 `std::priority_queue` 数据结构来实现 LRU。 下面是基于 `std::priority_queue` 实现 LRU 的代码示例: ```c++ #include <iostream> #include <queue> #include <unordered_map> template <typename T> class LRUCache { public: LRUCache(int capacity) : capacity_(capacity) {} void put(int key, const T& value) { if (cache_.find(key) != cache_.end()) { // 如果 key 已经存在,则更新 value 并移动到队首 auto it = cache_[key]; it->second = value; cache_list_.erase(it); cache_list_.push_front({key, value}); cache_[key] = cache_list_.begin(); } else { // 如果 key 不存在,则插入新的键值对,并将其移动到队首 if (cache_list_.size() == capacity_) { // 如果队列已满,则删除队尾元素 auto last = cache_list_.back(); cache_list_.pop_back(); cache_.erase(last.first); } cache_list_.push_front({key, value}); cache_[key] = cache_list_.begin(); } } const T* get(int key) { if (cache_.find(key) != cache_.end()) { // 如果 key 存在,则返回 value 并将其移动到队首 auto it = cache_[key]; cache_list_.erase(it); cache_list_.push_front(*it); cache_[key] = cache_list_.begin(); return &it->second; } else { // 如果 key 不存在,则返回 nullptr return nullptr; } } private: int capacity_; std::list<std::pair<int, T>> cache_list_; // 双向链表存储键值对 std::unordered_map<int, typename std::list<std::pair<int, T>>::iterator> cache_; // 哈希表存储键值对的迭代器 }; int main() { LRUCache<int> cache(3); cache.put(1, 10); cache.put(2, 20); cache.put(3, 30); cache.put(4, 40); std::cout << *cache.get(2) << std::endl; // 输出 20 std::cout << *cache.get(3) << std::endl; // 输出 30 std::cout << (cache.get(5) == nullptr) << std::endl; // 输出 1 return 0; } ``` 在上述实现中,我们使用了一个双向链表 `cache_list_` 存储键值对,同时使用一个哈希表 `cache_` 存储每个键对应的迭代器。在 `put` 操作中,如果缓存中已经存在该键,则更新该键对应的值并将其移动到队首;如果不存在该键,则首先判断缓存是否已满,若已满则删除队尾元素,然后将新的键值对插入到队首。在 `get` 操作中,如果缓存中存在该键,则返回其对应的值并将其移动到队首;如果不存在该键,则返回 nullptr。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值