Map+雙向鏈表實現LRU算法

  • map+雙向鏈表實現,其中雙向鏈表頭結點的後繼節點依次存儲最近使用的緩存數據,尾節點的前驅節點爲最久未被使用的數據;當通過key查詢緩存在map中,則將對應節點移動至頭結點的後面;key不在緩存中時,新建一個節點,並移動至頭結點後面。

  • 實現代碼如下所示:

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Map+雙向鏈表實現LRU
 *
 * @param <V>
 */
public class LRU<V> {
    // 緩存的數量
    private int capacity = 1024;

    // 緩存對應的map
    private Map<String, Node<String, V>> table = new ConcurrentHashMap<>();

    // 雙向鏈表頭結點
    private Node<String, V> head;

    // 雙向鏈表尾節點
    private Node<String, V> tail;


    public LRU(int capacity) {
        this();
        this.capacity = capacity;
    }

    public LRU() {
        head = new Node<>();
        tail = new Node<>();
        head.next = tail;
        head.pre = null;
        tail.pre = head;
        tail.next = null;
    }

    /**
     * 獲取緩存
     *
     * @param key
     * @return
     */
    public V get(String key) {
        // 如果key不在table裏面,說明緩存裏面沒有
        Node<String, V> currNode = table.get(key);
        if (currNode == null) {
            return null;
        }

        // 如果key存在table裏面,則將key對應的node放到對頭
        currNode.pre.next = currNode.next;
        currNode.next.pre = currNode.pre;

        moveNode2Head(currNode);

        return currNode.value;
    }

    /**
     * 將當前節點移動到鏈表尾部
     *
     * @param currNode
     */
    private void moveNode2Head(Node<String, V> currNode) {
        // 當前節點存在鏈表中要找到當前節點的位置,並把其刪除
        // HEAD->A
        currNode.next = head.next;
        head.next.pre = currNode;
        currNode.pre = head;
        head.next = currNode;
    }


    /**
     * 保存緩存
     *
     * @param key
     * @param v
     */
    public void put(String key, V v) {
        // 如果存在緩存裏面,更新當前node的位置
        Node<String, V> currNode = table.get(key);
        if (currNode == null) {
            // 如果不存在的話,判斷是否超過空間大小,如果超過空間大小,將尾部的節點刪除掉;如果沒有超過空間大小,插入到table裏面
            if (table.size() == capacity) {
                // 刪除當前節點
                table.remove(tail.pre.key);

                tail.pre.pre.next = tail;
                tail.pre = tail.pre.pre;
            }

            currNode = new Node();
            currNode.key = key;
            currNode.value = v;
            table.put(key, currNode);
        } else {
            currNode.pre.next = currNode.next;
            currNode.next.pre = currNode.pre;
        }

        moveNode2Head(currNode);
    }

    static class Node<K, V> {
        private K key;
        private V value;
        private Node<K, V> pre;
        private Node<K, V> next;

    }


    public static void main(String[] args) {
        LRU<Integer> lru = new LRU(20);

        for (int i = 0; i < 100; i++) {
            lru.put("a", 1);
            lru.put("b", 2);
            lru.put("c", 3);

            Integer a1 = lru.get("a");

            lru.put("c", 3);
            lru.put("d", 4);
            lru.put("e", 5);
            Integer a = lru.get("a");

            lru.put("e", 6);
            lru.put("f", 7);

            lru.put("i" + i / 10, i);
        }
        System.out.println(lru);

        while (lru.head != null) {
            System.out.println(lru.head.key + "-" + lru.head.value);
            lru.head = lru.head.next;
        }
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章