Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operation: get and set.
get(key) - Get the value (will always be positive) of the key if the key exists in the cache, otherwise return -1.
set(key, value) - Set or insert the value if the key is not already present. When the cache reached its capacity, it should invalidate the least recently used item before inserting a new item.
分析:数据结构实现问题。
1,看到get(key) 和set(key, value)两个方法,首先想到用HashMap. 但是如果直接使用HashMap存放key-value对,则没有办法知道元素的访问时间信息。
2,可以维持顺序信息的首先想到数组和链表,按照题目意思,如果某个元素被访问,则要放在头,还有插入操作,所以想到使用链表。
3,确定使用链表之后,链表节点存放value, HashMap存放key-node对,节点被访问后,则把此节点移到表头,这样,可以保证节点按照访问的新旧程度排列。由于超过capacity之后,要删除最旧访问的节点,所以要维持一个指向表尾的指针。为了O(1)时间删除节点,则用双向链表最为合适。
到此,基本确定了。
public class LRUCache {
//双向链表节点类
class DoubleLinkedListNode{
public int key;
public int value;
public DoubleLinkedListNode pre;
public DoubleLinkedListNode next;
public DoubleLinkedListNode(int key, int value){
this.key = key;
this.value = value;
}
}
private int capacity;
private int size;
private HashMap<Integer, DoubleLinkedListNode> map = new HashMap<Integer, DoubleLinkedListNode>();
private DoubleLinkedListNode head;
private DoubleLinkedListNode tail;
public LRUCache(int capacity) {
this.capacity = capacity;
size = 0;
}
//get和set调用原子操作方法实现逻辑
public int get(int key) {
if(map.containsKey(key)){
DoubleLinkedListNode curr = map.get(key);
removeNode(curr);
setHead(curr);
return curr.value;
}else{
return -1;
}
}
public void set(int key, int value) {
if(map.containsKey(key)){
DoubleLinkedListNode curr = map.get(key);
curr.value = value;
removeNode(curr);
setHead(curr);
}else{
DoubleLinkedListNode curr = new DoubleLinkedListNode(key, value);
map.put(key, curr);
setHead(curr);
if(size < capacity){
size++;
}else{
map.remove(tail.key);
removeNode(tail);
}
}
}
//两个基本操作就是删除节点和把节点设置为头结点,所以把两个功能分出来写成两个方法
private void removeNode(DoubleLinkedListNode node){
DoubleLinkedListNode pre = node.pre;
DoubleLinkedListNode next = node.next;
if(pre != null){
pre.next = next;
}else{
head = next;
}
if(next != null){
next.pre = pre;
}else{
tail = pre;
if(tail != null)
tail.next = null;
}
}
private void setHead(DoubleLinkedListNode node){
node.next = head;
node.pre = null;
if(head != null){
head.pre = node;
}
head = node;
if(tail == null)
tail = node;
}
}