Skip to content

Instantly share code, notes, and snippets.

@GorshkovNikita
Created June 30, 2019 17:10
Show Gist options
  • Save GorshkovNikita/660d554a43bbb7b74179f4b12547158b to your computer and use it in GitHub Desktop.
Save GorshkovNikita/660d554a43bbb7b74179f4b12547158b to your computer and use it in GitHub Desktop.
LRU cache implementation
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