1. 程式人生 > >快取淘汰演算法(LRU演算法)

快取淘汰演算法(LRU演算法)

LRU是Least Recently Used 的縮寫,翻譯過來就是“最近最少使用”,LRU快取就是使用這種原理實現,簡單的說就是快取一定量的資料,當超過設定的閾值時就把一些過期的資料刪除掉,比如我們快取10000條資料,當資料小於10000時可以隨意新增,當超過10000時就需要把新的資料新增進來,同時要把過期資料刪除,以確保我們最大快取10000條,那怎麼確定刪除哪條過期資料呢,採用LRU演算法實現的話就是將最老的資料刪掉,廢話不多說,下面來說下Java版的LRU快取實現

Java裡面實現LRU快取通常有兩種選擇,一種是使用LinkedHashMap,一種是自己設計資料結構,使用連結串列+HashMap

LinkedHashMap自身已經實現了順序儲存,預設情況下是按照元素的新增順序儲存,也可以啟用按照訪問順序儲存,即最近讀取的資料放在最前面,最早讀取的資料放在最後面,然後它還有一個判斷是否刪除最老資料的方法,預設是返回false,即不刪除資料,我們使用LinkedHashMap實現LRU快取的方法就是對LinkedHashMap實現簡單的擴充套件,擴充套件方式有兩種,一種是inheritance,一種是delegation,具體使用什麼方式看個人喜好

LinkedHashMap :
//LinkedHashMap的一個建構函式,當引數accessOrder為true時,即會按照訪問順序排序,最近訪問的放在最前,最早訪問的放在後面
public LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) {
        super(initialCapacity, loadFactor);
        this.accessOrder = accessOrder;
}

//LinkedHashMap自帶的判斷是否刪除最老的元素方法,預設返回false,即不刪除老資料
//我們要做的就是重寫這個方法,當滿足一定條件時刪除老資料 protected boolean removeEldestEntry(Map.Entry<K,V> eldest) { return false; }

採用inheritance方式實現比較簡單,而且實現了Map介面,在多執行緒環境使用時可以使用 Collections.synchronizedMap()方法實現執行緒安全操作

public class LRUCache2<K, V> extends LinkedHashMap<K, V> {
    private final int
MAX_CACHE_SIZE; public LRUCache2(int cacheSize) { super((int) Math.ceil(cacheSize / 0.75) + 1, 0.75f, true); MAX_CACHE_SIZE = cacheSize; } @Override protected boolean removeEldestEntry(Map.Entry eldest) { return size() > MAX_CACHE_SIZE; } @Override public String toString() { StringBuilder sb = new StringBuilder(); for (Map.Entry<K, V> entry : entrySet()) { sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue())); } return sb.toString(); } }

這樣算是比較標準的實現吧,實際使用中這樣寫還是有些繁瑣,更實用的方法時像下面這樣寫,省去了單獨見一個類的麻煩

final int cacheSize = 100;
Map<String, String> map = new LinkedHashMap<String, String>((int) Math.ceil(cacheSize / 0.75f) + 1, 0.75f, true) {
    @Override
    protected boolean removeEldestEntry(Map.Entry<String, String> eldest) {
    return size() > cacheSize;
    }
};

delegation方式實現更加優雅一些,但是由於沒有實現Map介面,所以執行緒同步就需要自己搞定了

public class LRUCache3<K, V> {

    private final int MAX_CACHE_SIZE;
    private final float DEFAULT_LOAD_FACTOR = 0.75f;
    LinkedHashMap<K, V> map;

    public LRUCache3(int cacheSize) {
        MAX_CACHE_SIZE = cacheSize;
        //根據cacheSize和載入因子計算hashmap的capactiy,+1確保當達到cacheSize上限時不會觸發hashmap的擴容,
        int capacity = (int) Math.ceil(MAX_CACHE_SIZE / DEFAULT_LOAD_FACTOR) + 1;
        map = new LinkedHashMap(capacity, DEFAULT_LOAD_FACTOR, true) {
            @Override
            protected boolean removeEldestEntry(Map.Entry eldest) {
                return size() > MAX_CACHE_SIZE;
            }
        };
    }

    public synchronized void put(K key, V value) {
        map.put(key, value);
    }

    public synchronized V get(K key) {
        return map.get(key);
    }

    public synchronized void remove(K key) {
        map.remove(key);
    }

    public synchronized Set<Map.Entry<K, V>> getAll() {
        return map.entrySet();
    }

    public synchronized int size() {
        return map.size();
    }

    public synchronized void clear() {
        map.clear();
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        for (Map.Entry entry : map.entrySet()) {
            sb.append(String.format("%s:%s ", entry.getKey(), entry.getValue()));
        }
        return sb.toString();
    }
}

LRU Cache的連結串列+HashMap實現

public class LRUCache1<K, V> {

    private final int MAX_CACHE_SIZE;
    private Entry first;
    private Entry last;

    private HashMap<K, Entry<K, V>> hashMap;

    public LRUCache1(int cacheSize) {
        MAX_CACHE_SIZE = cacheSize;
        hashMap = new HashMap<K, Entry<K, V>>();
    }

    public void put(K key, V value) {
        Entry entry = getEntry(key);
        if (entry == null) {
            if (hashMap.size() >= MAX_CACHE_SIZE) {
                hashMap.remove(last.key);
                removeLast();
            }
            entry = new Entry();
            entry.key = key;
        }
        entry.value = value;
        moveToFirst(entry);
        hashMap.put(key, entry);
    }

    public V get(K key) {
        Entry<K, V> entry = getEntry(key);
        if (entry == null) return null;
        moveToFirst(entry);
        return entry.value;
    }

    public void remove(K key) {
        Entry entry = getEntry(key);
        if (entry != null) {
            if (entry.pre != null) entry.pre.next = entry.next;
            if (entry.next != null) entry.next.pre = entry.pre;
            if (entry == first) first = entry.next;
            if (entry == last) last = entry.pre;
        }
        hashMap.remove(key);
    }

    private void moveToFirst(Entry entry) {
        if (entry == first) return;
        if (entry.pre != null) entry.pre.next = entry.next;
        if (entry.next != null) entry.next.pre = entry.pre;
        if (entry == last) last = last.pre;

        if (first == null || last == null) {
            first = last = entry;
            return;
        }

        entry.next = first;
        first.pre = entry;
        first = entry;
        entry.pre = null;
    }

    private void removeLast() {
        if (last != null) {
            last = last.pre;
            if (last == null) first = null;
            else last.next = null;
        }
    }


    private Entry<K, V> getEntry(K key) {
        return hashMap.get(key);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        Entry entry = first;
        while (entry != null) {
            sb.append(String.format("%s:%s ", entry.key, entry.value));
            entry = entry.next;
        }
        return sb.toString();
    }

    class Entry<K, V> {
        public Entry pre;
        public Entry next;
        public K key;
        public V value;
    }
}

LinkedHashMap的FIFO實現
FIFO是First Input First Output的縮寫,也就是常說的先入先出,預設情況下LinkedHashMap就是按照新增順序儲存,我們只需重寫下removeEldestEntry方法即可輕鬆實現一個FIFO快取,簡化版的實現程式碼如下

final int cacheSize = 5;
LinkedHashMap<Integer, String> lru = new LinkedHashMap<Integer, String>() {
    @Override
    protected boolean removeEldestEntry(Map.Entry<Integer, String> eldest) {
    return size() > cacheSize;
    }
};

相關推薦

快取淘汰演算法LRU演算法

LRU是Least Recently Used 的縮寫,翻譯過來就是“最近最少使用”,LRU快取就是使用這種原理實現,簡單的說就是快取一定量的資料,當超過設定的閾值時就把一些過期的資料刪除掉,比如我們快取10000條資料,當資料小於10000時可以隨意新增,當超

頁面置換演算法LRU演算法

LRU LRU是一種頁面置換演算法,在對於記憶體中但是又不用的資料塊,叫做LRU,作業系統會根據那些資料屬於LRU而將其移出記憶體而騰出空間來載入另外的資料 LRU演算法:最近最少使用,簡單來說就是將資料塊中,每次使用過的資料放在資料塊的最前端,然後將存在的

最佳淘汰演算法OPT 先進先出的演算法FIFO 最近最久未使用演算法LRU

#include<bits/stdc++.h> #define Del(a,b) memset(a,b,sizeof(a)) using namespace std; int a[4000]; //隨機生成的頁 int c;//使用者頁面容量 void i

作業系統頁面置換演算法之最近最少使用演算法LRU

import java.util.LinkedList; import java.util.List; public class LRU {public static void main(String[] args) {int framesize = 5;//幀數量int[] s = { 1, 2, 3, 4

為什麼我要放棄javaScript資料結構與演算法第一章—— JavaScript簡介

資料結構與演算法一直是我算比較薄弱的地方,希望通過閱讀《javaScript資料結構與演算法》可以有所改變,我相信接下來的記錄不單單對於我自己有幫助,也可以幫助到一些這方面的小白,接下來讓我們一起學習。 第一章 JavaScript簡介 眾所周知,JavaScript是一門非常強大的程式語言,不僅可以用於

小白python學習——機器學習篇——k-近鄰演算法KNN演算法

一、演算法理解 一般給你一資料集,作為該題目的資料(一個矩陣,每一行是所有特徵),而且每一組資料都是分了類,然後給你一個數據,讓這個你預測這組資料屬於什麼類別。你需要對資料集進行處理,如:歸一化數值。處理後可以用matplotlib繪製出影象,一般選兩個特徵繪製x,y軸,然後核心是計算出預測點到

機器學習實戰Apriori演算法關聯分析

目錄 0. 前言 1. Apriori 演算法尋找頻繁項集 2. 從頻繁項集中挖掘關聯規則 3. 實戰案例 3.1. apriori演算法發現頻繁項集和關聯規則 學習完機器學習實戰的Apriori,簡單的做個筆記。文中部分描述屬於

基於分解的多目標進化演算法MOEA/D

目錄 1、MOEA/D的特點 2、 MOEA/D的分解策略 3、MOEA/D的流程 基於分解的多目標進化演算法(Multi-objectiveEvolutionary Algorithm Based on Decomposition, MOEA/D)將多目標優化問題被轉

經典排序演算法Java版

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

關於離散小波框架變換以及多孔演算法a trous的學習感悟

最近學習小波變換與非抽取的小波變換,尤其是非抽取的小波變換,在學習感覺非常困惑,最後也得出一點感悟,不知是否正確,僅供參考,相互學習! 首先,我是在文獻[1]瞭解到離散小波框架的,在文獻[2]瞭解到多孔演算法的。學習過程中,查看了很多圖書以及網上的資料,講得都很抽象,部落格[3]對我的幫助很大。

LL(0)語法分析演算法完整版 ----編譯原理試驗

                                          &

常用演算法Java表述

 氣泡排序(Bubble Sort) 氣泡排序:一種交換排序,它的基本思想是:兩兩比較相鄰記錄的關鍵字,如果反序則交換,直到沒有反序的記錄為止。穩定排序演算法 時間複雜度 O(n2),裡層迴圈每趟比較第 j 項和第 j+1項,如果前項大於後項,則發生交換。缺點是每次比較後都可能發生交換,

深度學習中的優化演算法待更

    優化演算法可以使得神經網路執行的速度大大加快,機器學習的應用是一個高度依賴經驗的過程,伴隨著大量迭代的過程,需要訓練諸多的模型來找到最合適的那一個。其中的一個難點在於,深度學習沒有在大資料領域發揮最大的效果,我們可以利用一個巨大的資料集來訓練神經網路,

反向傳播演算法BP演算法

BP演算法(即反向傳播演算法),適合於多層神經元網路的一種學習演算法,它建立在梯度下降法的基礎上。BP網路的輸入輸出關係實質上是一種對映關係:一個n輸入m輸出的BP神經網路所完成的功能是從n維歐氏空間向m維歐氏空間中一有限域的連續對映,這一對映具有高度非線性。它的資訊處理能力來源於簡單非線性函式的多

累加和校驗演算法CheckSum演算法

因為外界總會對電路存在或多或少的干擾,對於數字訊號,很可能導致傳輸的資料出現千差萬別。對於很多需要傳輸資料的場合,尤其是一些資料可能會影響一些硬體的動作(諸如嵌入式的一些裝置、機器人等),錯誤的資料可能會帶來一些隱性風險,想想都可怕。 由於本人是嵌入式相關領域的,平時玩的都是微控制器,當然微

對稱矩陣與壓縮儲存演算法java實現

一、問題描述 實現一個對稱矩陣的壓縮儲存 二、演算法分析 對稱矩陣的特點:a[i][j] = a[j][i].即所有元素關於對角線對稱 所以可以將對稱矩陣的下三角儲存在一個數組物件SA中,儲存方式是, SA[0] = a[0][0] SA[1] = a[1][0]  

機器學習中的優化演算法附程式碼

摘要 > 優化演算法指通過改善訓練方式,來最小化(或最大化)損失函式E(x) 區域性最優問題 區域性最優與鞍點。在神經網路中,最小化非凸誤差函式的另一個關鍵挑戰是避免陷於多個其他區域性最小值中。實際上,問題並非源於區域性極小值,而是來自鞍點,即一個維度向上傾斜且

整合演算法ensemble learning--競賽和論文神器

就拿決策樹來說,比如如果一顆決策樹效果不行,就用多顆決策樹,這樣就構成隨機森林。 目的:讓機器學習效果更好,單個不行,就用多個一起。 整合演算法一、 bagging演算法:並行訓練多個M模型(如決策樹)取平均或者其他方式彙總,如果就拿決策樹來說,訓練M顆決策樹取預測資料,就會有M個結果,

【ML1】機器學習之EM演算法演算法詳細推導過程

        寫在前面的話:對於EM演算法(Expectation Maximization Algorithm, 最大期望演算法), 大家如果僅僅是為了使用,則熟悉演算法流程即可。此處的演算法推導過程,僅提供給大家進階 之用。對於其應用,

一種較為高效的TreeList生成演算法Delphi實現

記得不久前曾寫過篇關於TreeList生成的文章。雖然那個演算法裡,我已經有對葉節點做判斷,避免無用的Filter操作。但是非葉節點的Filter操作依然是無可避免的。而Filter又是影響整個生成的最重要因素,因此當帶子節點的節點很多時,速度還是要被拖下去的。 後來我看到了一種覺得不錯的思路,