Published:
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. Analysis The key to solve this problem is using a double linked list which enables us to quickly move nodes.The LRU cache is a hash table of keys and double linked nodes. The hash table makes the time of get() to be O(1). The list of double linked nodes make the nodes adding/removal operations O(1). Java Solution Define a double linked list node. class Node{ int key; int value; Node pre; Node next; public Node(int key, int value){ this.key = key; this.value = value; } } public class LRUCache { int capacity; HashMap
map = new HashMap (); Node head=null; Node end=null; public LRUCache(int capacity) { this.capacity = capacity; } public int get(int key) { if(map.containsKey(key)){ Node n = map.get(key); remove(n); setHead(n); return n.value; } return -1; } public void remove(Node n){ if(n.pre!=null){ n.pre.next = n.next; }else{ head = n.next; } if(n.next!=null){ n.next.pre = n.pre; }else{ end = n.pre; } } public void setHead(Node n){ n.next = head; n.pre = null; if(head!=null) head.pre = n; head = n; if(end ==null) end = head; } public void set(int key, int value) { if(map.containsKey(key)){ Node old = map.get(key); old.value = value; remove(old); setHead(old); }else{ Node created = new Node(key, value); if(map.size()>=capacity){ map.remove(end.key); remove(end); setHead(created); }else{ setHead(created); } map.put(key, created); } } } -- linked hash map implementation import java.util.LinkedHashMap; import java.util.Map; public class LRUCacheImpl extends LinkedHashMap { private static final long serialVersionUID = 1L; private int capacity; public LRUCacheImpl(int capacity, float loadFactor){ super(capacity, loadFactor, true); this.capacity = capacity; } /** * removeEldestEntry() should be overridden by the user, otherwise it will not * remove the oldest object from the Map. */ @Override protected boolean removeEldestEntry(Map.Entry eldest){ return size() > this.capacity; } public static void main(String arg[]){ LRUCacheImpl lruCache = new LRUCacheImpl(4, 0.75f); lruCache.put(1, "Object1"); lruCache.put(2, "Object2"); lruCache.put(3, "Object3"); lruCache.get(1); lruCache.put(4, "Object4"); System.out.println(lruCache); lruCache.put(5, "Object5"); lruCache.get(3); lruCache.put(6, "Object6"); System.out.println(lruCache); lruCache.get(4); lruCache.put(7, "Object7"); lruCache.put(8, "Object8"); System.out.println(lruCache); } } -- output {2=Object2, 3=Object3, 1=Object1, 4=Object4} {4=Object4, 5=Object5, 3=Object3, 6=Object6} {6=Object6, 4=Object4, 7=Object7, 8=Object8}