LRU的典型实现是double linked list + hash map。
双向链表根据每个节点最近被访问的时间有序存储,最近被访问的节点存储在表头,最近没有被访问的节点存储的表尾,存储依据是因为:最近被访问的节点在接下来的一段时间仍有很大的概率被再次访问到。
哈希表的作用是用来提高查找效率,如果不使用哈希表,则查找一个节点的时间复杂度是O(n),而使用了哈希表,则每个节点的查找时间复杂度为O(1)。
查找(GET)操作: 根据键值查找hashmap,如果没找到直接返回-1若找到对应节点node,则将其插入到双向链表表头返回node的value值
插入(SET)操作: 根据键值查找hashmap。如果找到,则直接将该节点移到表头即可如果没有找到,首先判断当前Cache是否已满如果已满,则删除表尾节点将新节点插入到表头
package com.dengpf.LRU;
import java.util.HashMap;
import java.util.LinkedHashMap;
/**
* Created by kobe73er on 16/12/16.
*/
public class LRUCache {
class Node {
int key;
int value;
Node pre;
Node next;
public Node(int key, int value) {
this.key = key;
this.value = value;
}
}
private HashMap<Integer, Node> hashMap;
private int size;
private Node head;
private Node tail;
private int capacity;
public LRUCache(int capacity) {
hashMap = new HashMap<Integer, Node>(capacity);
this.capacity = capacity;
size = 0;
this.head = null;
this.tail = null;
}
public int get(int key) {
Node node = hashMap.get(key);
if (node != null) {
moveNodeToHead(node);
return node.value;
}
return -1;
}
public void set(int key, int value) {
Node node = hashMap.get(key);
if (node == null) {
node = new Node(key, value);
if (size >= capacity) {
hashMap.remove(tail.key);
removeNodeFromTail();
} else {
size++;
}
} else {
node.value = value;
}
if (size == 1) {
head = node;
tail = node;
}
moveNodeToHead(node);
hashMap.put(key, node);
}
private void removeNodeFromTail() {
if (tail != null) {
if (tail.pre != null) {
tail.pre.next = null;
} else {
head = null;
}
tail = tail.pre;
}
}
private void moveNodeToHead(Node node) {
if (node == head) {
return;
}
if (node.next != null) {
node.next.pre = node.pre;
}
if (node.pre != null) {
node.pre.next = node.next;
}
if (node == tail) {
tail = node.pre;
}
if (head != null) {
node.next = head;
head.pre = node;
}
head = node;
node.pre = null;
}
public static void main(String[] args) {
LRUCache lruCache = new LRUCache(1);
lruCache.set(2, 1);
System.out.println(lruCache.get(2));
lruCache.set(3, 2);
System.out.println(lruCache.get(2));
System.out.println(lruCache.get(3));
}
}
/**
* Your LFUCache object will be instantiated and called as such:
* LFUCache obj = new LFUCache(capacity);
* int param_1 = obj.get(key);
* obj.set(key,value);
*/