最近最久未被使用(LRU)缓存机制(哈希链表)

在这里插入图片描述
LRU 缓存算法的核心数据结构就是哈希链表,双向链表和哈希表的结合体。这个数据结构长这样:
其实很简单:哈希表(unordered_map)中的键值对为unordered_map<int, list<pair<int, int>>::iterator>;双向链表(list)中的元素类型为list<pair<int, int>>
在这里插入图片描述
分析上面的操作过程,要让 put 和 get 方法的时间复杂度为O(1),我们可以总结出 cache 这个数据结构必要的条件:查找快,插入快,删除快,有顺序之分。

因为显然 cache 必须有顺序之分,以区分最近使用的和久未使用的数据;而且我们要在 cache 中查找键是否已存在;如果容量满了要删除最后一个数据;每次访问还要把数据插入到队头。

那么,什么数据结构同时符合上述条件呢?哈希表查找快,但是数据无固定顺序;链表有顺序之分,插入删除快,但是查找慢。所以结合一下,形成一种新的数据结构:哈希链表。

代码实现如下:(这个时候STL用起来就很舒服了)

class LRUCache {
private:
	int capacity;
	// 双端链表:装着 (key, value) 二元组
	list<pair<int, int>>cache;
	//哈希表中存着(key,key在list中的迭代器)
	unordered_map<int, list<pair<int, int>>::iterator>mp;
public:
	LRUCache(int capacity) {
		this->capacity = capacity;
	}

	int get(int key) {
		//unordered_map<int, list<pair<int, int>>::iterator>::iterator it = mp.find(key);
		auto it = mp.find(key);
		if (it == mp.end())// key 不存在
		{
			return -1;
		}
		// key 存在,把 (k, v) 换到队头
		pair<int, int> temp = *mp[key];
		cache.erase(mp[key]);
		cache.push_front(temp);
		// 更新哈希表
		mp[key] = cache.begin();

		return temp.second;
	}

	void put(int key, int value) {
		//要先判断 key 是否已经存在
		auto it = mp.find(key);
		if (it == mp.end())//key不存在
		{
			//还要判断cache是否满了
			if (cache.size() == this->capacity)//满了
			{
				//删除链表尾结点
			    // 注意cache 和 map 中的数据都要删除
				pair<int,int>temp=cache.back();//尾元素的引用
				cache.pop_back();
				mp.erase(temp.first);//在map中删除键为temp.first的二元组
			}
			//开始put
			cache.push_front(make_pair(key,value));
			mp.insert(make_pair(key,cache.begin()));
		}
		else//key存在
		{
			//map中更新value,list中删除旧的二元组,并把新的二元组放到链表头
			cache.erase(mp[key]);
			cache.push_front(make_pair(key, value));

			mp[key] = cache.begin();
		}
	}
};
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页