我试图理解下面的LRU实现。无法弄清楚以下内容:
addFirst()
有什么用?正在从put
和get
方法调用此方法。这些问题可能听起来很愚蠢,但我真的很感激解释。
代码:
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
public class LRUDLL<K, V> {
private final Map<K, Entry<K,V>> map;
private Entry<K, V> oldest;
private final int lruSize;
public LRUDLL (int lruSize) {
if(lruSize <= 0){
throw new IllegalArgumentException("Size is inappropriate");
}
map = new HashMap<K, Entry<K, V>>();
this.lruSize = lruSize;
}
private static class Entry<K, V> {
Entry<K, V> left;
Entry<K, V> right;
K key;
V value;
Entry(Entry<K, V> left, K key, V value, Entry<K, V> right) {
this.left = left;
this.key = key;
this.value = value;
this.right = right;
}
};
private void addFirst(Entry<K, V> entry) {
remove(entry);
if(oldest == null) {
entry.left = entry.right = entry;
oldest = entry;
} else {
Entry<K, V> tail = entry;
tail.right = entry;
entry.left = tail;
//deal with circulating
oldest.left = entry;
entry.right = oldest;
}
}
private void remove (Entry<K, V> entry) {
assert entry != null;
if(entry.left != null) entry.left.right = entry.right;
if(entry.right != null) entry.right.left = entry.left;
if(entry == oldest) oldest = entry.right;
}
public synchronized void put (K key, V value) {
Entry<K, V> entry = new Entry<K, V>(null, key, value, null);
map.put(key, entry);
addFirst(entry);
if(removeOldestEntry()) {
remove(oldest);
}
}
public synchronized V get(K key) {
Entry<K, V> entry = map.get(key);
if(entry!= null) {
addFirst(entry);
return entry.value;
}
return null;
}
private boolean removeOldestEntry() {
return map.size() > lruSize;
}
}
答案 0 :(得分:1)
addFirst()有什么用?从两者调用此方法 放置和获取方法。
最近使用的数据结构需要在访问条目时更新。当您put
时,您希望将条目添加到前面,因为它是最近使用的。当你从LRU get
输入一个条目时,它也是最近使用过的条目,所以把它带到LRU的前面。
双重链表如何帮助追踪最早的条目?一切 条目实际上在一个条目不知道的地图中 另一个。
查看LinkedHashMap
的实施情况。双向链表保持访问顺序。每个条目都知道在它之前和之后访问了哪个条目。
答案 1 :(得分:1)
我认为这里的关键点是它不仅仅是一个双向链表,而是一个循环双向链表。因此oldest
是至少 - 最近使用的元素,oldest.right
是第二个 - 最近使用的元素,。 。 。 oldest.left
是最 - 最近使用过的元素。 (并且oldest.left.left
是第二大 - 最近使用的元素,依此类推。)
我不确定为什么会这样做 - 似乎更简单的是让oldest
指向最近最少使用的newest
指向最...最近使用过 - 但这并不重要。
addFirst()
有什么用?正在从put
和get
方法调用此方法。
addFirst
从列表中的当前位置删除指定的条目,并将其添加到oldest
的左侧,从而将其标记为最近使用的元素。
双重链表如何帮助追踪最早的条目?所有条目实际上都在地图中,其中一个条目不知道另一个条目。
嗯,所以这个实现中存在一个严重的错误:它实际上从来没有从map
删除任何元素,所以它实际上不是LRU缓存。更糟糕的是,它永远不会使left
和right
对它应该“删除”的条目归零,这意味着随后从map
检索这些条目,然后重新{{1 - ed,列表序列完全错误。所以实施很糟糕。
但假设如何工作是这样的:addFirst
只有所有条目,但它不知道哪个是最近最少使用的。该列表按照最近使用的顺序保留所有元素,因此在任何给定时间,map
是最近最少使用的。
(该错误的根本原因是oldest
被用于两个单独的事情:remove
只需要它从列表中的位置删除元素,因此它可以移动到一个新职位,而addFirst
实际上需要能够从put
中删除oldest
。可能map
的当前版本应该内联到remove
,并且应该创建一个实际删除最旧元素的新addFirst
。)