# 算法思路
LRU 算法的淘汰策略是 Least Recently Used
,也就是每次淘汰那些最久没被使用的数据
LRU 算法的核心数据结构是使用哈希表和链表,首先借助链表的有序性使得链表元素维持插入顺序,同时借助哈希映射的快速访问能力使得我们可以在 O(1) 时间访问链表的任意元素。
- LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存 int get(int key) 如果关键字 key 存在于缓存中,则返回关键字的值,否则返回 -1 。
- void put(int key, int value) 如果关键字 key 已经存在,则变更其数据值 value ;如果不存在,则向缓存中插入该组 key-value 。如果插入操作导致关键字数量超过 capacity ,则应该 逐出 最久未使用的关键字。
# 代码实现
先实现Node
和DoubleList
,再实现LURCache
中的抽象方法makeRecently
、deleteKey
、addRecently
、removeLeastRecently
class LRUCache {
private HashMap<Integer,Node> map;
private DoubleList cache;
private int cap;
public LRUCache(int capacity) {
cap = capacity;
map = new HashMap<>();
cache = new DoubleList();
}
public void makeRecently(int key){
// 先删除再添加到尾部
Node x = map.get(key);
cache.remove(x);
cache.addLast(x);
}
public void deleteKey(int key){
Node x = map.get(key);
cache.remove(x);
map.remove(key);
}
public void addRecently(int key, int val){
// 直接添加到尾部
Node x = new Node(key,val);
cache.addLast(x);
map.put(key, x);
}
public void removeLeastRecently(){
Node x = cache.removeFirst();
map.remove(x.key);
}
public int get(int key) {
if(!map.containsKey(key)){
return -1;
}
makeRecently(key);
return map.get(key).val;
}
public void put(int key, int value) {
if(map.containsKey(key)){
deleteKey(key);
addRecently(key, value);
} else {
if(map.size() == cap){
removeLeastRecently();
}
addRecently(key, value);
}
}
}
class Node {
public int key;
public int val;
public Node next;
public Node prev;
public Node(int k, int v){
key = k;
val = v;
}
}
class DoubleList {
private int size;
private Node head;
private Node tail;
public DoubleList(){
head = new Node(0,0);
tail = new Node(0,0);
head.next = tail;
tail.prev = head;
}
public void addLast(Node x){
x.prev = tail.prev;
x.next = tail;
tail.prev.next = x;
tail.prev = x;
size++;
}
public void remove(Node x){
x.prev.next = x.next;
x.next.prev = x.prev;
size--;
}
// 删除First其实是删除leastRecentlyNode
public Node removeFirst(){
if(head.next == tail){
return null;
}
Node first = head.next;
remove(first);
return first;
}
public int size(){
return size;
}
}