Created
June 30, 2019 17:10
-
-
Save GorshkovNikita/660d554a43bbb7b74179f4b12547158b to your computer and use it in GitHub Desktop.
LRU cache implementation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class LRUCache { | |
private Map<Integer, CacheNode> cache; | |
private int capacity; | |
private CacheNode head; | |
private CacheNode tail; | |
private static class CacheNode { | |
public int key; | |
public int value; | |
public CacheNode next; | |
public CacheNode prev; | |
public CacheNode(int key, int value) { | |
this.key = key; | |
this.value = value; | |
} | |
} | |
public LRUCache(int capacity) { | |
this.capacity = capacity; | |
this.cache = new HashMap<>(capacity); | |
} | |
public int get(int key) { | |
if (cache.containsKey(key)) { | |
CacheNode cacheNode = cache.get(key); | |
update(cacheNode); | |
return cacheNode.value; | |
} else { | |
return -1; | |
} | |
} | |
public void put(int key, int value) { | |
if (cache.size() == capacity && !cache.containsKey(key)) { | |
// если элемент не найден, то мы должны удалить tail, | |
// чтобы вместо него добавить новый элемент | |
// tail и head должны существовать, так как capacity > 0 | |
// но они могут являться ссылкой на один и тот же элемент | |
// если tail == head, то нужно отдельно обработать | |
cache.remove(tail.key); | |
if (tail == head) { | |
tail = null; | |
head = null; | |
} else { | |
// здесь неважно где голова, главное, что она есть | |
tail.next.prev = null; | |
tail = tail.next; | |
} | |
} | |
CacheNode cacheNode; | |
if (cache.containsKey(key)) { | |
cacheNode = cache.get(key); | |
cacheNode.value = value; | |
// тоже самое, что в get | |
update(cacheNode); | |
} else { | |
cacheNode = new CacheNode(key, value); | |
// head может быть == null, это значит, что и tail == null | |
if (head == null) { | |
head = cacheNode; | |
tail = cacheNode; | |
} else { | |
head.next = cacheNode; | |
cacheNode.prev = head; | |
head = cacheNode; | |
} | |
} | |
cache.put(key, cacheNode); | |
} | |
public void update(CacheNode cacheNode) { | |
// если извлекаемый элемент является головой, то оставляем все как есть, | |
// это значит, что он и так последним юзался | |
if (head != cacheNode) { | |
// если извлекаемый элемент является хвостом, то мы должны переставить его в начало | |
if (tail == cacheNode) { | |
// меняем хвост на новый | |
tail = cacheNode.next; | |
// удаляем ссылку на извлекаемый элемент | |
tail.prev = null; | |
} else { | |
// если не является ни хвостом, ни голоой, | |
// то переставляем ссылку предыдущего элемента на следующий | |
cacheNode.prev.next = cacheNode.next; | |
// и, соответственно, наоборот | |
cacheNode.next.prev = cacheNode.prev; | |
} | |
// делаем извлекаемый элемент головой, а старой голове добавляем ссылку на этот элемент | |
// также старую голову делаем предыдущим элементом для новой головы | |
cacheNode.prev = head; | |
head.next = cacheNode; | |
head = cacheNode; | |
cacheNode.next = null; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment