算法 | LRU算法

一.簡介

LRU是什麼?按照英文的直接原義就是Least Recently Used,最近最久未使用法,它是按照一個非常著名的計算機操作系統基礎理論得來的:最近使用的頁面數據會在未來一段時期內仍然被使用,已經很久沒有使用的頁面很有可能在未來較長的一段時間內仍然不會被使用。基於這個思想,會存在一種緩存淘汰機制,每次從內存中找到最久未使用的數據然後置換出來,從而存入新的數據!它的主要衡量指標是使用的時間,附加指標是使用的次數。在計算機中大量使用了這個機制,它的合理性在於優先篩選熱點數據,所謂熱點數據,就是最近最多使用的數據!因爲,利用LRU我們可以解決很多實際開發中的問題,並且很符合業務場景。

二.java實現LRU的完整代碼:

import java.util.HashMap;
 
public class LRU<K, V> {
    private int currentSize;//當前的大小
    private int capcity;//總容量
    private HashMap<K, Node> caches;//所有的node節點
    private Node first;//頭節點
    private Node last;//尾節點
 
    public LRU(int size) {
        currentSize = 0;
        this.capcity = size;
        caches = new HashMap<K, Node>(size);
    }
 
    /**
     * 放入元素
     * @param key
     * @param value
     */
    public void put(K key, V value) {
        Node node = caches.get(key);
        //如果新元素
        if (node == null) {
            //如果超過元素容納量
            if (caches.size() >= capcity) {
                //移除最後一個節點
                caches.remove(last.key);
                removeLast();
            }
            //創建新節點
            node = new Node(key,value);
        }
        //已經存在的元素覆蓋舊值
        node.value = value;
        //把元素移動到首部
        moveToHead(node);
        caches.put(key, node);
    }
 
    /**
     * 通過key獲取元素
     * @param key
     * @return
     */
    public Object get(K key) {
        Node node = caches.get(key);
        if (node == null) {
            return null;
        }
        //把訪問的節點移動到首部
        moveToHead(node);
        return node.value;
    }
 
    /**
     * 根據key移除節點
     * @param key
     * @return
     */
    public Object remove(K key) {
        Node node = caches.get(key);
        if (node != null) {
            if (node.pre != null) {
                node.pre.next = node.next;
            }
            if (node.next != null) {
                node.next.pre = node.pre;
            }
            if (node == first) {
                first = node.next;
            }
            if (node == last) {
                last = node.pre;
            }
        }
        return caches.remove(key);
    }
 
    /**
     * 清除所有節點
     */
    public void clear() {
        first = null;
        last = null;
        caches.clear();
    }
 
    /**
     * 把當前節點移動到首部
     * @param node
     */
    private void moveToHead(Node node) {
        if (first == node) {
            return;
        }
        if (node.next != null) {
            node.next.pre = node.pre;
        }
        if (node.pre != null) {
            node.pre.next = node.next;
        }
        if (node == last) {
            last = last.pre;
        }
        if (first == null || last == null) {
            first = last = node;
            return;
        }
        node.next = first;
        first.pre = node;
        first = node;
        first.pre = null;
    }
 
    /**
     * 移除最後一個節點
     */
    private void removeLast() {
        if (last != null) {
            last = last.pre;
            if (last == null) {
                first = null;
            } else {
                last.next = null;
            }
        }
    }
 
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        Node node = first;
        while (node != null) {
            sb.append(String.format("%s:%s ", node.key, node.value));
            node = node.next;
        }
        return sb.toString();
    }
     
 
    public static void main(String[] args) {
        LRU<Integer, String> lru = new LRU<Integer, String>(5);
        lru.put(1, "a");
        lru.put(2, "b");
        lru.put(3, "c");
        lru.put(4,"d");
        lru.put(5,"e");
        System.out.println("原始鏈表爲:"+lru.toString());
 
        lru.get(4);
        System.out.println("獲取key爲4的元素之後的鏈表:"+lru.toString());
 
        lru.put(6,"f");
        System.out.println("新添加一個key爲6之後的鏈表:"+lru.toString());
 
        lru.remove(3);
        System.out.println("移除key=3的之後的鏈表:"+lru.toString());
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章