LRU緩存簡單實現

第一次看到這個題目,我懵逼了,啥是LRU,因而乎我去百度了一下,大概的意思是這樣的,LRU是Least Recently Used的縮寫,即最近最少使用,選擇最近最久未使用的key予以淘汰。 大概瞭解後我想到(實際想了半天。。。而且還參考了網上的其餘人的一些思路)node

既然要頻繁的刪除和插入,那確定首選鏈表,大概思路分以下幾步: 1.須要一個雙向鏈表,頭節點和尾節點 2.HashMap存儲key, HashMap的Value爲雙向鏈表LRU的Node節點 3.put插入時判斷該key是否存在,若是不存在,再判斷是否空間滿了,滿了就刪除末尾節點(最少使用節點),而後把新插入元素放到頭節點,若是沒滿則插入到鏈表頭節點,若是已存在,則移動該節點到頭節點 4.get獲取節點時有則返回,而且把該節點移動到鏈表的頭節點bash

代碼實現以下:測試

/**
 * 雙向鏈表
 */
class LinkNode {

    /**
     * 前節點
     */
    LinkNode pre;
    /**
     * 後節點
     */
    LinkNode next;
    int key;
    int val;
}

public class LRUCache {
    private int capacity;
    private LinkNode head;
    private LinkNode tail;
    private HashMap<Integer,LinkNode> cache;

    public LRUCache(int capacity) {
        this.capacity=capacity;
        cache = new HashMap<>(capacity);
    }

    public int get(int key) {
        LinkNode res = cache.get(key);
        if(res == null){
            return -1;
        }
        moveNodeToFirst(res);
        return res.val;
    }

    public void put(int key, int value) {
        LinkNode tempLinkNode = cache.get(key);
        if(tempLinkNode == null){
            if(cache.size() >= capacity){
                removeLastNode();
            }
            tempLinkNode = new LinkNode();
            tempLinkNode.key = key;
        }
        tempLinkNode.val = value;
        moveNodeToFirst(tempLinkNode);
        cache.put(key, tempLinkNode);
    }

    /**
     * put或者get時移動該節點到鏈表的頭節點
     * @param node
     */
    private void moveNodeToFirst(LinkNode node) {
        //空鏈表時放入第一個元素
        if(head == null){
            tail = head = node;
            return;
        }
        //鏈表的頭部
        if (head == node) {
            return;
        }
        //鏈表的尾部
        else if(tail == node){
            //把他前面的節點變成尾節點(他要被移動到鏈表開頭了)
            tail = tail.pre;
        }
        //在鏈表中間的節點
        else if(node.next != null || node.pre != null){
            //節點被移動到頭部後,相鄰節點的先後節點值變化
            assert node.pre != null;
            node.pre.next = node.next;
            assert node.next != null;
            node.next.pre = node.pre;
        }

        //原來的鏈表頭部,變成第二個
        node.next = head;
        //節點被移動到頭部後,相鄰節點的先後節點值變化
        head.pre = node;
        //放到頭部後他的前節點爲空
        node.pre = null;
        //放到鏈表頭部
        head = node;
    }

    /**
     * 超過hashMap容量時刪除最後一個元素,即最少使用元素
     */
    private void removeLastNode() {
        LinkNode tempLinkNode = tail;
        //倒數第二個節點變成最後一個節點
        tail = tail.pre;
        if(tail != null){
            tail.next = null;
        }else{
            head = null;
        }
        cache.remove(tempLinkNode.key);
    }
}

複製代碼

測試ui

public static void main(String[] args) {
        LRUCache cache = new LRUCache( 2 );
        cache.put(1, 1);
        cache.put(2, 2);
        System.out.println("獲取1的值" + cache.get(1));
        cache.put(3, 3);
        System.out.println("key:3已插入, key:2,被刪除");
        System.out.println("獲取2的值" + cache.get(2));
        cache.put(4, 4);
        System.out.println("key:4已插入, key:1,被刪除");
        System.out.println("獲取1的值" + cache.get(1));
        System.out.println("獲取3的值" + cache.get(3));
        System.out.println("獲取4的值" + cache.get(4));
    }
複製代碼

結果this

獲取1的值:1
key:3已插入, key:2,被刪除
獲取2的值:-1
key:4已插入, key:1,被刪除
獲取1的值-1
獲取3的值:3
獲取4的值:4
複製代碼

參考資料:cloud.tencent.com/developer/a… www.jianshu.com/p/34c03210c…spa

相關文章
相關標籤/搜索