这是2019年阿里巴巴的一道面试题:
题目:LRU 缓存机制 设计和实现一个 LRU(最近最少使用)缓存数据结构,使它应该支持一下操作:get 和 put。 get(key) - 如果 key 存在于缓存中,则获取 key 的 value(总是正数),否则返回 -1。 put(key,value) - 如果 key 不存在,请设置或插入 value。当缓存达到其容量时,它应该在插入新项目之前使最近最少使用的项目作废。
出题人:文景/阿里云 CDN 资深技术专家
这里基于双向链表+HashMap实现该数据结构:
//大体思路:建立虚拟头尾节点,构建双端链表
public class LRUCache {
class Node{
int key;
int value;
Node pre;
Node next;
}
//将节点加到双端链表头部
private void addNode(Node node) {
node.pre=head;
node.next=head.next;
head.next.pre=node;
head.next=node;
}
//删除接节点
private void removeNode(Node node) {
Node pre=node.pre;
Node next=node.next;
pre.next=next;
next.pre=pre;
}
//将访问的节点移动到双端列表首位(head的后一位,head为虚拟节点)
private void moveToHead(Node node) {
removeNode(node);
addNode(node);
}
//获取双端链表尾节点,tail节点的前一位
private Node popTail() {
Node res=tail.pre;
removeNode(res);
return res;
}
//存储所有的元素
private HashMap<Integer, Node> cache=new HashMap<>();
private int size;
private int capacity;
private Node head,tail;
public LRUCache(int capacity) {
this.size=0;
this.capacity=capacity;
head=new Node();
tail=new Node();
head.next=tail;
tail.pre=head;
}
public int get(int key) {
Node node=cache.get(key);
if(node==null) {
return -1;
}
moveToHead(node);
return node.value;
}
public void put(int key,int value) {
Node node=cache.get(key);
if(node==null) {
Node newNode=new Node();
newNode.key=key;
newNode.value=value;
cache.put(key, newNode);
addNode(newNode);
++size;
if(size>capacity) {
Node tail=popTail();
cache.remove(tail.key);
--size;
}
}else {
node.value=value;
moveToHead(node);
}
}
}