题目:
运用你所掌握的数据结构,设计和实现一个 LRU (最近最少使用) 缓存机制。它应该支持以下操作: 获取数据 get 和 写入数据 put 。
获取数据 get(key) - 如果关键字 (key) 存在于缓存中,则获取关键字的值(总是正数),否则返回 -1。
写入数据 put(key, value) - 如果关键字已经存在,则变更其数据值;如果关键字不存在,则插入该组「关键字/值」。当缓存容量达到上限时,它应该在写入新数据之前删除最久未使用的数据值,从而为新的数据值留出空间。
示例:
LRUCache cache = new LRUCache( 2 /* 缓存容量 */ );
cache.put(1, 1);
cache.put(2, 2);
cache.get(1); // 返回 1
cache.put(3, 3); // 该操作会使得关键字 2 作废
cache.get(2); // 返回 -1 (未找到)
cache.put(4, 4); // 该操作会使得关键字 1 作废
cache.get(1); // 返回 -1 (未找到)
cache.get(3); // 返回 3
cache.get(4); // 返回 4
个人思路:
LRU 缓存机制可以通过哈希表辅以双向链表实现,我们用一个哈希表和一个双向链表维护所有在缓存中的键值对。
双向链表按照被使用的顺序存储了这些键值对,靠近头部的键值对是最久未使用的,而靠近尾部的键值对是最近使用的。
哈希表即为普通的哈希映射(HashMap),通过缓存数据的键映射到其在双向链表中的位置。
这样以来,我们首先使用哈希表进行定位,找出缓存项在双向链表中的位置,随后将其移动到双向链表的头部,即可在 O(1)的时间内完成 get 或者 put 操作。
代码:
class Tree{
int val;
int key;
Tree pre;
Tree next;
Tree(int key,int val){
this.key=key;
this.val=val;
}
}
class LRUCache {
int capacity;
HashMap<Integer,Tree> map=new HashMap();
Tree head;
Tree end;
public LRUCache(int capacity) {
this.capacity=capacity;
head=new Tree(0,0);
end=new Tree(100,100);
head.next=end;
end.pre=head;
}
public int get(int key) {
if(!map.containsKey(key)){
return -1;
}
Tree curtree=map.get(key);
int re=curtree.val;
curtree.pre.next=curtree.next;
curtree.next.pre=curtree.pre;
curtree.next=end;
curtree.pre=end.pre;
end.pre.next=curtree;
end.pre=curtree;
return re;
}
public void put(int key, int value) {
if(map.containsKey(key)){
Tree curtree=map.get(key);
curtree.pre.next=curtree.next;
curtree.next.pre=curtree.pre;
curtree.next=null;
curtree.pre=null;
Tree new_curtree=new Tree(key,value);
new_curtree.next=end;
new_curtree.pre=end.pre;
end.pre.next=new_curtree;
end.pre=new_curtree;
map.put(key,new_curtree);
}else{
Tree new_curtree=new Tree(key,value);
new_curtree.next=end;
new_curtree.pre=end.pre;
end.pre.next=new_curtree;
end.pre=new_curtree;
map.put(key,new_curtree);
if(map.size()>capacity){
Tree dele_tree=head.next;
int dele_key=dele_tree.key;
map.remove(dele_key);
head.next=dele_tree.next;
dele_tree.pre=null;
dele_tree.next=null;
head.next.pre=head;
}
}
}
}