1. 程式人生 > >LRU緩存

LRU緩存

amp node break 範型 app 緩存 index size 計算

實現摘要:map+雙向鏈表

Java中的LinkedHashMap本身自帶lru屬性。

java實現:v1版本

feature

  • 實現基本的lru語義
  • 不能擴容
  • evict回調
  • 範型
public interface LruCache<K, V> {
   V get(K key);
   V put(K key, V value);
   V remove(K key);
   int size();
}
public class LruCacheImpl<K, V> implements LruCache<K, V> {

    static class Node<K, V> {
        Node<K, V> prev;
        Node<K, V> next;
        Node<K, V> nextE;
        K key;
        V value;
        public Node() {

        }

        public Node (Node<K, V> prev, Node<K, V> next, Node<K, V> nextE, K key, V value) {
            this.prev = prev;
            this.next = next;
            this.nextE = nextE;
            this.key = key;
            this.value = value;
        }

        @Override
        public String toString() {

            return "[key: " + key + ", value:" + value + "]";
        }
    }

    private Node<K, V> head = new Node<>(null, null, null, null, null), rear = head;
    private int threshold = 0, size = 0;

    public LruCacheImpl(int threshold) {
        this.threshold = threshold;
    }

    private int capacity = 128;
    private Node<K, V>[] bucket = new Node[capacity];

    @Override
    public V get(K key) {
        //計算hash
        int index = indexFor(key);
        Node<K, V> e;
        if ((e = bucket[index]) != null) {
            for (;e != null;) {
                if (e.key == key || e.key.equals(key)) {
                    //adjust bi linked list
                    linkToLast(e);
                    return e.value;
                }
                e = e.nextE;
            }
        }
        return null;
    }

    @Override
    public V put(K key, V value) {
        //計算hash
        int index = indexFor(key);
        Node<K, V> e;
        if ((e = bucket[index]) != null) {
            for (;e != null;) {
                if (e.key == key || e.key.equals(key)) {
                    V old = e.value;
                    e.value = value;
                    //adjust bi linked list
                    linkToLast(e);
                    return old;
                }
                e = e.nextE;
            }
        }
        //insert
        Node<K, V> node = new Node<>(rear, null,null, key, value);
        rear.next = node;
        rear = node;
        if (head.next == null) {
            head.next = node;
        }
        bucket[index] = node;
        size++;
        if (size > threshold) {
            int toDelNum = size - threshold;
            Node<K, V> p = head.next;
            for (int i = 0; i < toDelNum && p != null; i++, p = p.next) {
                remove(p.key);
                onEvict(p);
            }
        }
        return value;
    }

    //callback
    private void onEvict(Node<K,V> p) {
        System.out.println("evict : " + p);
    }

    private void linkToLast(Node<K,V> e) {
        if (e == rear) return;
        //先刪除該節點
        e.next.prev = e.prev;
        e.prev.next = e.next;

        rear.next = e;
        e.next = null;
        e.prev = rear;

        rear = e;
    }

    private int indexFor(K key) {
        int hash = key.hashCode();
        return hash % capacity;
    }

    @Override
    public V remove(K key) {
        //計算hash
        int index = indexFor(key);
        Node<K, V> e;
        if ((e = bucket[index]) != null) {
            if (e.key == key || e.key.equals(key)) {
                bucket[index] = e.nextE;
            } else {
                for (Node<K, V> pre = e, cur = e.nextE; cur != null; pre = cur, cur = cur.nextE) {
                    if (cur.key == key || cur.key.equals(key)) {
                        //delete node @ bi linked list
                        pre.nextE = cur.nextE;
                        cur.nextE = null;
                        e = cur;
                        break;
                    }
                }
            }
            //delete e @ bi linked list
            size--;

            if (e == rear) {
                rear = e.prev;
                rear.next = null;
            } else {
                e.prev.next = e.next;
                e.next.prev = e.prev;
            }
            e.next = null;
            e.prev = null;
            return e.value;
        }
        return null;
    }

    @Override
    public int size() {
        return size;
    }

    public void list() {
        StringBuilder sb = new StringBuilder();
        for (Node<K, V> e = head.next; e != null; e = e.next) {
            sb.append("\n[key=").append(e.key).append(", value=").append(e.value).append("]");
        }
        System.out.println(sb.toString());
    }
}

LRU緩存