簡體   English   中英

刪除 java 中的元素表單鏈表,意外行為

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM