算法:LRU(最近最少使用)


算法:LRU(最近最少使用)

本文參考自小灰文章:https://mp.weixin.qq.com/s/B5xiVeW22ZumbI9KfrYJSg

LRU算法

什么是LRU算法

  LRU算法又稱最近最少使用算法,它的基本思想是長期不被使用的數據,在未來被用到的幾率也不大,所以當新的數據進來時我們可以優先把這些數據替換掉

  在LRU算法中,使用了一種有趣的數據結構,稱為哈希鏈表。我們知道哈希表是由多個<Key,Value>對組成的,哈希鏈表是將這寫節點鏈接起來,每一個節點都有一個前驅結點和后驅節點,就像雙向鏈表中的節點一樣。哈希表擁有了固定的排列順序。

  

  基於哈希鏈表的有序性,我們就可以把<Key,Value>按照最后的使用時間來排列。

LRU算法的基本思路

  假設我們使用哈希鏈表來緩存用戶信息,目前緩存了4個用戶,用戶按照時間順序從鏈表右端插入:

  

  情景一:當訪問用戶5時,由於哈希鏈表中沒有用戶5的數據,從數據庫中讀取出來插入到緩存中

  

  情景二:擋訪問用戶2時,由於哈希鏈表中有用戶2的數據,我們把它掐斷,放到鏈表最右段

  

  

  情景三:同情景二,這次訪問用戶4的數據

  

  情景四:當用戶訪問用戶6,用戶6在緩存中沒有,需要插入到鏈表中,但此時鏈表長度已滿,我們把最左端的用戶刪掉,然后插入用戶6

  

說明:我們仔細回顧一下,當緩存命中時,我們就把它放到最右端,也就是說排在右邊的是最近被使用過的,那左邊的當然是相對較少被訪問過的,所以當緩存不命中的時候,我們就把最左邊的剔除掉,所以這里就體現了最近最少使用的原則。

LRU算法的基本實現

public class LRUCache{
    private int limit;
    private HashMap<String,Node> hashMap;
    private Node head;
    private Node end;

    public LRUCache(int limit)
    {
        this.limit = limit;
        hashMap = new HashMap<String,Node>();
    }

    public String get(String key){
        Node node = hashMap.get(key);
        if(node ==null)
            return null;
        refreshNode(node);
        return node.value;
    }

    public void put(String key,String value){
        Node node = hashMap.get(key);
        if(node == null){
            if(hashMap.size()>=limit)
            {
                String oldKey = removeNode(head);
                hashMap.remove(oldKey);
            }
            node = new Node(key,value);
            addNode(node);
            hashMap.put(key,node)
        }else{
            node.value = value;
            refreshNode(node);
        }
    }

    public void remove(String key){
        Node node = hashMap.get(key);
        removeNode(node);
        hashMap.remove(key);
    }


    /**
     * 刷新剛被訪問的節點位置
     */
    private void refreshNode(Node node)
    {
        if(node == end)
            return;
        removeNode(node);
        addNode(node);
    }

    
    /**
     * 刪除節點
     */

    public String removeNode(Node node){
        if(node == end)
            //刪除尾節點
            end = end.pre;
        else if(node ==head)
            //刪除頭節點
            head = head.next;
        else
            {
                //移除中間節點
                node.pre.next = node.next;
                node.next.pre = node.pre;
            }
        return node.key;
    }
    
    /**
     * 尾部插入節點
     */

     public void addNode(Node node)
     {
        if(end!=null)
        {
            end.next = node;
            node.pre = end;
            node.next = null;
        }
        end = node;
        if(head == null)
            head = node;
     }

}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM