[英]Removing an element form linked list in java, unexpected behavior
我正在尝试使用 hashmap 和链表在 java 中实现 lru 缓存:
public static class LRUCache{
LinkedList<Integer> ll;
HashMap<Integer, Integer> map;
//HashSet<Integer> map;
int size;
LRUCache(int n){
ll = new LinkedList<>();
map = new HashMap<>();
size=n;
}
int refer(int page){
if(map.containsKey(page)){
Integer it = map.get(page);
//System.out.println("m.get(page)= " + map.get(page));
//System.out.println(it + " it+page " + page);
ll.remove(it);
} else{
if(map.size() >= size){
map.remove(ll.getLast());
ll.removeLast();
}
}
ll.addFirst(page);
//System.out.println(page + " page+peek " + ll.peekFirst());
map.put(page, ll.peekFirst());
return page;
}
}
在上面的参考 function 中,对于在 map 中找到页面的 if 条件,该值已成功从链接列表中删除,我认为这不应该工作,因为我只保留 Z1D78DC8ED51214E51AEZB51144 中的页面值。 现在有趣的是,当我把 ll.remove(page); 在上面的代码中,尽管页面和它的值相同,但它会中断。
int refer(int page){
if(map.containsKey(page)){
Integer it = map.get(page);
//System.out.println("m.get(page)= " + map.get(page));
//System.out.println(it + " it+page " + page);
ll.remove(page);
} else{
if(map.size() >= size){
map.remove(ll.getLast());
ll.removeLast();
}
}
ll.addFirst(page);
//System.out.println(page + " page+peek " + ll.peekFirst());
map.put(page, ll.peekFirst());`enter code here`
return page;
}
我对这种行为感到非常惊讶。
对于下面的测试案例,代码的第一个价格有效,第二个无效,唯一的区别是 ll.remove(it) 和 ll.remove(page),它和 page 的值是一样的。
void printCache(){
System.out.print("| ");
for(int i=0;i<ll.size();i++){
System.out.print(ll.get(i) + " |" + " ");
}
System.out.println();
}
}
public static void main(String[] args) {
LRUCache lruCache = new LRUCache(4);
lruCache.refer(11);
lruCache.refer(12);
lruCache.refer(13);
lruCache.printCache();
lruCache.refer(11);
lruCache.printCache();
lruCache.refer(14);
lruCache.printCache();
lruCache.refer(13);
lruCache.printCache();
lruCache.refer(15);
lruCache.printCache();
}
保留两个集合对于缓存来说很昂贵,为什么不使用单个集合。 Linkedhashmap 保持插入顺序。 此外,您必须牢记并发性。 也许两个同时命中会使您丢失数据。 只需用 Collections.synchronizedMap 包装 map。 Linkedhashmap 可以保留长类型的密钥。 您可以将时间(以毫秒为单位)作为键。 然后您可以通过键搜索找到最后使用的元素,或者只是简单地删除最后插入的元素。
无需深入了解代码的太多细节,调用ll.remove(page)
和调用 ll.remove ll.remove(it)
时调用的方法之间存在很大差异。
调用ll.remove(it)
时, it
的类型是Integer
,所以调用的方法是LinkedList.remove(Object)
。 从此方法的文档中:
从此列表中删除第一次出现的指定元素(如果存在)....
而当你调用ll.remove(page)
时, page
的类型是int
,所以你实际上调用了: LinkedList.remove(int)
。 从此方法的文档中:
删除此列表中指定 position 处的元素....
一种方法是删除page
处的索引,而另一种方法是删除it
匹配的值。
我认为您在调用ll.remove(page)
以实现类似行为时可能想要做的是ll.remove(new Integer(page))
这是一个演示此问题的简单代码:
public static void foo(int x) {
System.out.println("Called foo(int)");
}
public static void foo(Integer x) {
System.out.println("Called foo(Integer)");
}
public static void main (String[] args) throws java.lang.Exception
{
int page = 5;
Integer it = new Integer(10);
foo(page);
foo(it);
foo(new Integer(page));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.