数据结构: LRU(LeastRecentlyUsed) 最近最少使用

LRU(LeastRecentlyUsed) 最近最少使用

原理

LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也更高”

详情看漫画图解LRU

实现

为了使得查找 插入 和删除都有较高的性能.

  • 通过一个双向链表(std::list)保存数据,和一个哈希表(std::unordered_map).

  • 哈希表保存每个节点的地址,可以基本保证在O(1)的时间负责度内找到节点.

  • 双向链表的插入和删除效率高.

    将新插入的节点放到链表的头部,尾部的链表是比较少访问的.

具体实现:

插入节点:
  • 存在,则更新其

    然后将该节点放到链表的头部.并且更新哈希表.

  • 不存在,则创建一个新的节点插入

    插入时,若缓存区已经满了.

    则需将链表的尾节点从链表和哈希表删除.

    若缓存未满,直接插入.

    最后将 新节点和其索引更新进哈希表

取节点:
  • 不存在,直接返回NULL

  • 存在

    从哈希表中获得其索引,然后在列表中取到该 键值对.

    将这个节点更新到链表头部.

    同时哈希表该节点在列表中的索引.

LeetCode 146. LRU Cache

#include "MyInclude.h"
/*
Design and implement a data structure for Least Recently Used (LRU) cache.
It should support the following operations: get and put.

get(key) - Get the value (will always be positive) of the key
if the key exists in the cache, otherwise return -1.

put(key, value) - Set or insert the value
if the key is not already present.

When the cache reached its capacity,
it should invalidate the least recently used item before inserting a new item.

Follow up:
Could you do both operations in O(1) time complexity?
在常数的时间复杂度要求下完成

*/
/**
* Your LRUCache object will be instantiated and called as such:
* LRUCache obj = new LRUCache(capacity);
* int param_1 = obj.get(key);
* obj.put(key,value);
*/


// Least Recently Used (LRU) https://blog.csdn.net/wydyd110/article/details/84023688
// list::splice https://blog.csdn.net/Wchenchen0/article/details/83058928

namespace pro146_0 {

	class LRUCache {
	public:

		class CacheNode {
		public:
			int key;
			int value;
			CacheNode(int key, int value) :key(key), value(value) {

			}
		};

		int capacity;
		list<CacheNode*> m_list;
		unordered_map<int, list<CacheNode*>::iterator> m_map;
		/*
		m_map存放的是key,迭代器
		m_list存放的是 key,value节点,并且,最新的节点放到最前面,而最少用的节点放在了后面
		*/
		LRUCache(int capacity) {
			this->capacity = capacity;
		}

		int get(int key) {
			// 找不到
			if (m_map.find(key) == m_map.end()) {
				return -1;
			} else {
				m_list.splice(m_list.begin(), m_list, m_map[key]);
				m_map[key] = m_list.begin();
				return m_list.front()->value;
			}

		}

		void put(int key, int value) {
			/*
			插入节点:
			1. 节点已经存在,跟新节点.并将节点放到最前面.

			2. 节点不存在,在链表最前面插入一个节点
			需要检查是否已经满了
			*/
			if (m_map.find(key) == m_map.end()) {
				if (m_list.size() == capacity) {
					// 把链表的最后一个元素从链表和哈希表中删除
					m_map.erase(m_list.back()->key);
					m_list.pop_back();
				}
				// 插入新节点
				m_list.push_front(new CacheNode(key, value));
				m_map[key] = m_list.begin();
			} else {
				// 已经存在更新域值
				m_list.splice(m_list.begin(), m_list, m_map[key]);
				m_map[key] = m_list.begin();
				m_list.front()->value = value;
			}

		}
	};

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值