Design and implement a data structure for Least Recently Used (LRU) cache. It should support the following operations: 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.
Ref: http://www.cnblogs.com/feiling/p/3426967.html
[解题思路]
LRU是Least Recently Used 的缩写,翻译过来就是“最不常使用”,也就是说,LRU缓存把最不常使用的数据移除,让给最新读取的数据。大多数情况下,最常读取的,也是读取次数最多的,所以,利用LRU缓存,我们能够提高系统的performance. LRU cache是非常频繁出现的一道面试题,一般来讲,当我们问到这道题时,面试官往往想得到的答案是利用 doubly linked list + hashtable 实现 LRU Cache, 那么我们现在就来讲一讲如何利用doubly linked list + hashtable实现LRU Cache的。
这里为什么使用Doubly linkd list 而不使用 Linked list的原因是:
当访问一个节点后,我们需要将他从原来的list中删除,然后将它插入到头节点处,删除过程中需要将其前后节点连接起来,单链表做不到。
查询:
- 根据键值查询hashmap,若命中,则返回节点,否则返回null。
- 从双向链表中删除命中的节点,将其重新插入到表头。
- 所有操作的复杂度均为O(1)。
插入:
- 将新的节点关联到Hashmap
- 如果Cache满了,删除双向链表的尾节点,同时删除Hashmap对应的记录
- 将新的节点插入到双向链表中头部
更新:
- 和查询相似
删除:
- 从双向链表和Hashmap中同时删除对应的记录。
-
1 public class LRUCache { 2 private DoubleLinkNode first; 3 private DoubleLinkNode last; 4 private int capacity; 5 private int currentSize; 6 private HashMap<Integer, DoubleLinkNode> nodesMap; 7 8 9 public LRUCache(int capacity){ 10 this.capacity = capacity; 11 currentSize = 0; 12 nodesMap = new HashMap<Integer, DoubleLinkNode>(); 13 14 } 15 16 public int get(int key){ 17 DoubleLinkNode node = nodesMap.get(key); 18 if(node != null){ 19 moveToHead(node); 20 return node.value; 21 }else{ 22 return -1; 23 } 24 } 25 26 public void set(int key, int value){ 27 DoubleLinkNode node = nodesMap.get(key); 28 if(node == null){ 29 if(currentSize >= capacity){ 30 nodesMap.remove(last.key); 31 removeLast(); 32 }else{ 33 currentSize++; 34 } 35 node = new DoubleLinkNode(); 36 } 37 38 if(currentSize == 1){ 39 first = node; 40 last = node; 41 } 42 43 node.key = key; 44 node.value = value; 45 moveToHead(node); 46 nodesMap.put(key,node); 47 } 48 49 private void moveToHead(DoubleLinkNode node){ 50 if(node == first) 51 return; 52 53 if(last == node){ 54 last = node.front; 55 } 56 // delete current node from doubly linked list 57 if(node.front != null){ 58 node.front.back = node .back; 59 } 60 61 if(node.back != null){ 62 node.back.front = node.front; 63 } 64 65 if(first != null){ 66 node.back = first; 67 first.front = node; 68 } 69 70 first = node; 71 node.front = null; 72 } 73 74 private void removeLast(){ 75 if(last != null){ 76 if(last.front != null){ 77 last.front.back = null; 78 }else{ 79 first = null; 80 } 81 last = last.front; 82 } 83 } 84 } 85 86 class DoubleLinkNode{ 87 DoubleLinkNode front; 88 DoubleLinkNode back; 89 int key; 90 int value; 91 }