开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第6天,点击查看活动详情
如何使用HashMap和双链表实现LRU缓存
LRU缓存代表最近最少使用的缓存。驱逐最近使用最少的条目。缓存的目的是提供快速和有效的方法检索数据。它需要满足一定的要求。
存在以下需求:
- 固定大小:缓存需要有一些边界来限制内存使用。
- 快速访问:缓存插入和查找操作应该是快速的,最好是O(1)时间。
- 在达到内存限制的情况下替换条目:当内存满时,缓存应该有有效的算法来驱逐条目。
在LRU缓存的情况下,我们驱逐最近最少使用的条目,所以我们必须跟踪最近使用的条目,长时间未使用的条目和最近使用的条目。另外查找和插入操作应该足够快。
当我们想到O(1)查找时,我们想到的明显的数据结构是HashMap。HashMap提供O(1)插入和查找。但是HashMap没有跟踪最近查询过哪些条目的机制。
为了跟踪这一点,我们需要另一种数据结构,它可以提供快速的插入、删除和更新,在LRU的情况下,我们使用双链表。选择双LinkList的原因是如果我们有需要执行此操作的Node的地址,则需要O(1)删除、更新和插入。
所以我们实现的LRU缓存将有HashMap和doublelinkedlist。HashMap将保存双链表节点的键和地址。doublelinkedlist将保存键的值。
由于我们需要跟踪最近使用的条目,我们将使用一个聪明的方法。我们将从底部删除元素,并在LinkedList的开始添加元素,无论何时任何条目被访问,它都将移动到顶部。因此,最近使用的条目将在顶部,最少使用的条目将在底部。
import java.util.HashMap;
class Entry {
int value;
int key;
Entry left;
Entry right;
}
public class LRUCache {
HashMap<Integer, Entry> hashmap;
Entry start, end;
int LRU_SIZE = 4; // Here i am setting 4 to test the LRU cache
// implementation, it can make be dynamic
public LRUCache() {
hashmap = new HashMap<Integer, Entry>();
}
public int getEntry(int key) {
if (hashmap.containsKey(key)) // Key Already Exist, just update the
{
Entry entry = hashmap.get(key);
removeNode(entry);
addAtTop(entry);
return entry.value;
}
return -1;
}
public void putEntry(int key, int value) {
if (hashmap.containsKey(key)) // Key Already Exist, just update the value and move it to top
{
Entry entry = hashmap.get(key);
entry.value = value;
removeNode(entry);
addAtTop(entry);
} else {
Entry newnode = new Entry();
newnode.left = null;
newnode.right = null;
newnode.value = value;
newnode.key = key;
if (hashmap.size() > LRU_SIZE) // We have reached maxium size so need to make room for new element.
{
hashmap.remove(end.key);
removeNode(end);
addAtTop(newnode);
} else {
addAtTop(newnode);
}
hashmap.put(key, newnode);
}
}
public void addAtTop(Entry node) {
node.right = start;
node.left = null;
if (start != null)
start.left = node;
start = node;
if (end == null)
end = start;
}
public void removeNode(Entry node) {
if (node.left != null) {
node.left.right = node.right;
} else {
start = node.right;
}
if (node.right != null) {
node.right.left = node.left;
} else {
end = node.left;
}
}
public static void main(String[] args) throws java.lang.Exception {
// your code goes here
LRUCache lrucache = new LRUCache();
lrucache.putEntry(1, 1);
lrucache.putEntry(10, 15);
lrucache.putEntry(15, 10);
lrucache.putEntry(10, 16);
lrucache.putEntry(12, 15);
lrucache.putEntry(18, 10);
lrucache.putEntry(13, 16);
System.out.println(lrucache.getEntry(1));
System.out.println(lrucache.getEntry(10));
System.out.println(lrucache.getEntry(15));
}
}