LRU算法
什么是LRU算法
LRU算法又叫删除最近最未使用算法,是一种缓存淘汰策略。
计算机中的容量是有限的,如果内存满了的话,那么就要删除旧的数据来满足让新数据可以填充进入,那么问题来了,什么样的数据就是要被删除的数据?
LRU缓存算法是一种常用的策略。全名又称Least Recently Used,也就是说我们认为最近使用过的数据应该是是「有用的」,很久都没用过的数据应该是无用的,内存满了就优先删那些很久没用过的数据。
使用场景
比如说现在有一个鞋柜,里面可以存放6双鞋,每新买一双鞋,你都要将新鞋存放进入,每次存放的时候,你都会判断一下是否有空余的位子,如果有空位子的话,你就可以成功存放进去,如果没有的话,你就需要忍痛割爱,把最近未穿(时间最长)的那双鞋拿出来,给新鞋腾出位置,让新鞋入库。这个就是典型的LRU设计思路。
希望我拿鞋举例子,可以让你们对LRU算法有一定的了解。相信你们一定可以的。
算法设计思路
LRU 缓存机制可以通过哈希表辅以双向链表实现,我们用一个哈希表和一个双向链表维护所有在缓存中的键值对。
-
双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最近使用的,而靠近尾部的键值对是最久未使用的。
-
哈希表即为普通的哈希映射(HashMap),通过缓存数据的键映射到其在双向链表中的位置。
如图所示,在双向链表中头部数据总为活跃度最高的节点,尾部为活跃度最低的节点,若容器已满的话,首先会淘汰尾部节点,将新数据插入头部,以此保证头部总是活跃度最高的节点。
具体实现
- 首先定义数据结构,存放该节点的k值,v值,前继节点和后继节点
/**数据结构*/
class CacheNode {
Object key; // 键
Object value; // 值
CacheNode next; // 后继节点
CacheNode pre; // 前继节点
}
- 定义全局变量:容器(caches),容量大小(capacity),容器中头节点(head)和尾节点(tail)
/**缓存容器*/
HashMap<K, CacheNode> caches;
/**容量大小*/
private int capacity;
/**头结点*/
private CacheNode head;
/**尾节点*/
private CacheNode tail;
- 初始化容器大小,通过构造方法进行初始化
/**实例化*/
public LRUCache(int size) {
// 容器大小
this.capacity = size;
// 实例化容器
caches = new HashMap<K, CacheNode>(size);
}
- 编写put方法
/**
* 添加k-v
* @param k 键
* @param v 值
* @return 值
*/
public V put(K k, V v) {
// 1. 从容器中查找是否存在
Cache