注意::
(1)LRU中head,tail是两个dummy节点,在构造方法中都指向了两个节点,这样的好处是统一进行添加和删除操作,而不用针对头,尾节点进行另外的删除操作!!
2. PUT操作时,如果是需要更新,那么先把需要更新的节点从双向链表中断开,再移动到头部;如果是新增的,需要考虑是否需要置换,置换时需要把hashMap中的key删除掉
import java.util.HashMap;
public class LRU<K,V> {
private HashMap<K,Node<K,V>> map;
private int size;
private Node<K,V> head;
private Node<K,V> tail;
private static class Node<K,V>{
Node<K,V> prev;
Node<K,V> next;
K key;
V value;
public Node(K key, V value) {
this.key = key;
this.value = value;
}
}
public LRU(int size) {
head = new Node<>(null,null);
tail = new Node<>(null,null);
head.next = tail;
tail.prev = head;
map = new HashMap<>(size);
this.size = size;
}
public V get(K key){
Node<K, V> node = map.get(key);
if(node == null) return null;
//先移除该节点
removeNode(node);
//然后把该节点插到头节点后面
insertAfterHead(node);
return node.value;
}
public void put(K key, V val){
Node<K, V> node = map.get(key);
//需要更新值,并且需要移动到头部
if(node != null){
node.value = val;
removeNode(node);
}else{
//LRU已满,需要置换末尾节点
if(map.size() == size){
//Node<K, V> removeNode = map.remove(tail.prev.key);
//removeNode(removeNode);
removeNode(map.remove(tail.prev.key));
}
node = new Node<>(key,val);
map.put(key,node);
}
insertAfterHead(node);
}
public void removeNode(Node<K,V> node){
node.prev.next = node.next;
node.next.prev = node.prev;
}
public void insertAfterHead(Node<K,V> node){
node.next = head.next;
head.next.prev = node;
head.next = node;
node.prev = head;
}
public static void main(String[] args) {
LRU<Integer,String> lru = new LRU<>(2);
lru.put(0,"zero");
lru.put(1,"one");
lru.put(2,"two");
System.out.println(lru.get(0));
}
}
output
null
TIPS:
面试场上,最好是不要使用JAVA提供的LinkedHashMap,因为面试官希望看到你自己手搓一个!!你能搓出来,是很加分的!!