LRU 緩存淘汰算法的兩種實現

It's always the attention to detail and the little grace notes that really make something sing. 專一細節愈出彩,別緻心思定成敗。

本文主要分享了LRU 緩存淘汰算法兩種實現。重要的不是實現,並且思想!node

全部源碼均已上傳至github:連接git

定義

LRU(Least Recently Used)最近最少使用策略就像它的名字同樣,是根據數據的歷史訪問記錄來進行淘汰數據的,其思想是「若是數據最近被訪問過,那麼未來被訪問的概率也更高;長期不被使用的數據在未來用到的概率也不大;當數據所佔內存達到必定的閾值時,將移除最近最少被使用的數據」。

舉例

好比一個書櫃(容量爲10),我會把我本身的書籍放進去,其中有兩本書籍是我最喜歡的,常常翻閱,可是隨着個人購買,書櫃會逐漸放滿(內存溢出),這時候就須要用到LRU的思想了,把我不常常看的,從書櫃裏拿出,放進箱子裏,而後再把新買的書籍放進書櫃。github

再 好比Redis,它是基於內存的,可是內存也不是無窮大的,當內存佔用達到一個閾值的時候,它就可使用LRU等一系列緩存算法,或者是將數據存到硬盤裏。算法

具體的實現代碼以下:數組

基於鏈表

鏈表初始化,申請capacity大小的內存空間

private LRUByLinkedList(int capacity) {
        head = null;
        size = capacity;
        count = 0;
    }複製代碼

模擬LRU的訪問(若是沒有該數據,則插入頭部)

注意:該if-else語句不能交換順序,不然會出現鏈表已滿,而且該數據已存在的狀況沒法處理。緩存

private void insert(int data) {
        Node preNode = findNode(data);
        if (null != preNode) {
            delete(preNode);
        } else {
            if (count >= size) {//鏈表滿
                deleteToTail();
            }
        }
        insertToHead(data);
    }複製代碼

刪除指定數據方法,常規刪除

private void delete(Node preNode) {
        System.out.println("刪除指定元素:" + preNode.next.data);
        preNode.next = preNode.next.next;
        --count;
    }複製代碼

刪除鏈表尾部數據

private void deleteToTail() {
        Node node = head;
        Node curNode = null;
        while (null != node.next) {
            curNode = node;
            node = node.next;
        }
        if (null != curNode) {
            System.out.println("鏈表已滿,刪除尾部元素:" + curNode.next.data);
            curNode.next = null;
        }
        --count;
    }複製代碼

在頭部插入數據

private void insertToHead(int data) {
        Node node = new Node(data, null);
        if (null == head) {
            head = node;
        } else {
            node.next = head;
        }
        head = node;
        ++count;
    }
複製代碼

測試結果以下

  1. 首先將capacity大小的鏈表插滿
  2. 當插入capacity+1個數據時,須要刪除尾部數據
  3. 當插入的數據存在的時候,將它從其位置刪除,而且插入頭部


基於數組

數據比較鏈表實現起來更爲簡單,在此不作闡述,直接上代碼。

private LRUByArray(int capacity) {
        arrays = new int[capacity];
        size = capacity;
        count = 0;
    }複製代碼

private void insert(int data) {
        int index = findValue(data);
        if (-1 != index) {
            delete(index);
        } else {
            if (count >= size) {//數組滿
                deleteToTail();
            }
        }
        insertToHead(data);
    }複製代碼

private void delete(int index) {
        //經過數據遷移的方式將該值刪除
        for (int i = index + 1; i < count; i++) {
            arrays[i - 1] = arrays[i];
        }
        System.out.println("刪除元素...");
        --count;
    }複製代碼

private void deleteToTail() {
        --count;//標記刪除法,實際上數組還存有該元素
        System.out.println("刪除尾部元素...");
    }複製代碼

private void insertToHead(int data) {
        if (count > 1) {
            for (int i = count - 1; i > -1; --i) {
                arrays[i + 1] = arrays[i];
            }
        }
        arrays[0] = data;
        ++count;
    }複製代碼

測試結果以下


注意:由於有大量頻繁的訪問致使數據遷移頻繁,所以數組並不適合作這種事情,能夠考慮加一個HaspMap作緩存,避免數據的頻繁遷移。

end


您的點贊和關注是對我最大的支持,謝謝!
相關文章
相關標籤/搜索