class LRUCache {
// key -> Node<key,val>
private HashMap<Integer, Node> map;
// Node(k1,v1) <-> Node(k2,v2)
private DoubleList cache;
// 最大容量
private int cap;
public LRUCache(int capacity) {
this.cap = capacity;
map = new HashMap<>();
cache = new DoubleList();
}
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);
return;
}
if(cap == cache.size()){
// 删除最久未使用的元素
removeLeastRecently();
}
//添加新元素为最近使用的元素
addRecently(key, value);
}
// 将某个key提升为最近使用的
private void makeRecently(int key){
Node x = map.get(key);
// 先从链表中删除这个节点
cache.remove(x);
//重新插到队尾
cache.addLast(x);
}
// 添加最近使用的元素
private void addRecently(int key, int val){
Node x = new Node(key, val);
// 链表尾部就是最近使用的元素
cache.addLast(x);
//在map中添加key的映射
map.put(key, x);
}
// 删除某一个key
private void deleteKey(int key){
Node x = map.get(key);
// 从链表中删除
cache.remove(x);
// 从map中删除
map.remove(key);
}
// 删除最久未使用的元素
private void removeLeastRecently(){
// 链表头部的第一个元素就是最久未使用的
Node deleteNode = cache.removeFirst();
// 删除map中的映射
int deletedKey = deleteNode.key;
map.remove(deletedKey);
}
}
// 定义双向链表的节点
// 默认 key和value为int类型
class Node{
public int key,val;
public Node next,prev;
public Node(int k, int v){
this.key = k;
this.val = v;
}
}
// 构建一个双向链表
class DoubleList{
// 定义头尾虚节点
private Node head, tail;
// 链表元素数
private int size;
public DoubleList(){
// 初始化双向链表
head = new Node(0,0);
tail = new Node(0,0);
head.next = tail;
tail.prev = head;
size = 0;
}
// 在链表尾部添加节点x,时间为O(1)
public void addLast(Node x){
x.prev = tail.prev;
x.next = tail;
tail.prev.next = x;
tail.prev = x;
size++;
}
// 删除链表中的x节点(x一定存在)
// 由于是双链表且给的是目标Node节点,时间为O(1)
public void remove(Node x){
x.prev.next = x.next;
x.next.prev = x.prev;
size--;
}
//删除链表中第一个节点,并返回该节点,时间O(1)
public Node removeFirst(){
if(head.next == null){
return null;
}
Node first = head.next;
remove(first);
return first;
}
// 返回链表的长度,时间O(1)
public int size(){
return size;
}
}