LRU緩存
阿新 • • 發佈:2018-10-05
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緩存