LRU
LRU:least recently use 最近最长使用
这是bilibili里面的一个最常访问。当然他们的数据结构肯定不是这样实现的了。
但这是一个比较好理解的LRU。长度固定,经常访问的放在前面。由于长度固定,那么多余的肯定像后排了。当然,bilibili这个肯定不是的,有可能是用Redis zSet来实现的。
class LRUCache {
class DLinkedNode {
int key;
int value;
DLinkedNode prev;
DLinkedNode next;
public DLinkedNode(){ }
public DLinkedNode(int key,int value){
this.key = key;
this.value = value;
}
}
private Map<Integer,DLinkedNode> cache = new HashMap<>();
private int size;
private int capacity;
private DLinkedNode head,tail;
public LRUCache(int capacity){
this.size = 0;
this.capacity = capacity;
head = new DLinkedNode();
tail = new DLinkedNode();
head.next = tail;
tail.prev = head;
}
public int get(int key){
DLinkedNode node = cache.get(key);
if (node == null){
return -1;
}
moveToHead(node);
return node.value;
}
public void put(int key,int value){
DLinkedNode node = cache.get(key);
if (node == null){
DLinkedNode newNode = new DLinkedNode(key,value);
cache.put(key,newNode);
addToHead(newNode);
++size;
if (size > capacity){
DLinkedNode tail = removeTail();
cache.remove(tail.key);
--size;
}
}else{
node.value = value;
moveToHead(node);
}
}
private void addToHead(DLinkedNode node){
node.prev = head;
node.next = head.next;
head.next.prev = node;
head.next = node;
}
private void removeNode(DLinkedNode node){
node.prev.next = node.next;
node.next.prev = node.prev;
}
private void moveToHead(DLinkedNode node){
removeNode(node);
addToHead(node);
}
private DLinkedNode removeTail(){
DLinkedNode res = tail.prev;
removeNode(res);
return res;
}
}
/**
* 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);
*/
上面代码解析
- 我们在放入hash里面,可以实现0(1)形式的检索key.value
- 如何我们放入的这个对象是一个双向链表,可以实现迅速放入头节点。以及删除尾节点。
- 当然我们这个DLinkedNode.里面保存了两个prev,next节点的引用。引用的大小都是相同的。