分佈式系統-常用算法實現-緩存算法

常用算法 LRU

對算法的解釋如下:
訪問某個節點時,將其從原來的位置刪除,並重新插入到鏈表頭部。這樣就能保證鏈表尾部存儲的就是最近最
久未使用的節點,當節點數量大於緩存最大空間時就淘汰鏈表尾部的節點。
爲了使刪除操作時間複雜度爲 O(1),就不能採用遍歷的方式找到某個節點。HashMap 存儲着 Key 到節點的映
射,通過 Key 就能以 O(1) 的時間得到節點,然後再以 O(1) 的時間將其從雙向隊列中刪除。
 
基於 雙向鏈表 + HashMap LRU 算法實現:
package com.cheri.suanfa;

import java.util.HashMap;
import java.util.Iterator;

/**
 * @author Aaron Du
 * @version V1.0
 * @date 2020/4/23 14:30
 **/
public class LRU<K, V> implements Iterable<K> {
    private Node head;
    private Node tail;
    private HashMap<K, Node> map;
    private int maxSize;

    private class Node {
        Node pre;
        Node next;
        K k;
        V v;

        public Node(K k, V v) {
            this.k = k;
            this.v = v;
        }
    }

    public LRU(int maxSize) {
        this.maxSize = maxSize;
        this.map = new HashMap<>(maxSize * 4 / 3);
        head = new Node(null, null);
        tail = new Node(null, null);
        head.next = tail;
        tail.pre = head;
    }

    public V get(K key) {
        if (!map.containsKey(key)) {
            return null;
        }
        Node node = map.get(key);
        unlink(node);
        appendHead(node);
        return node.v;
    }

    public void put(K key, V value) {
        if (map.containsKey(key)) {
            Node node = map.get(key);
            unlink(node);
        }
        Node node = new Node(key, value);
        map.put(key, node);
        appendHead(node);
        if (map.size() > maxSize) {
            Node toRemove = removeTail();
            map.remove(toRemove.k);
        }
    }

    private void unlink(Node node) {
        Node pre = node.pre;
        Node next = node.next;
        pre.next = next;
        next.pre = pre;
        node.pre = null;
        node.next = null;
    }

    private void appendHead(Node node) {
        Node next = head.next;
        node.next = next;
        next.pre = node;
        node.pre = head;
        head.next = node;
    }

    private Node removeTail() {
        Node node = tail.pre;
        Node pre = node.pre;
        tail.pre = pre;
        pre.next = tail;
        node.pre = null;
        node.next = null;
        return node;
    }

    @Override
    public Iterator<K> iterator() {
        return new Iterator<K>() {
            private Node cur = head.next;

            @Override
            public boolean hasNext() {
                return cur != tail;
            }

            @Override
            public K next() {
                Node node = cur;
                cur = cur.next;
                return node.k;
            }
        };
    }


    public static void main(String[] args) {
        LRU<String,Integer> lru = new LRU<String, Integer>(20);
        lru.put("a",1);
        lru.put("b",2);
        lru.put("c",3);
        lru.put("d",4);
        lru.put("e",5);

        Iterator iterator = lru.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

        System.out.println(lru.get("a"));
        System.out.println("=======獲取元素後=============>");

        Iterator iterator2 = lru.iterator();
        while (iterator2.hasNext()){
            System.out.println(iterator2.next());
        }

    }
}


##運行後結果如下: 可以清楚看到 再次訪問的a元素被放在首節點了。 

 

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