LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是如果数据最近被访问过,那么将来被访问的几率也更高。
public class LRUCache<K,V> {
static class Node{
Node pre;
Node next;
Object key;
Object value;
}
/**当前缓存对象数量*/
private int currentCacheSize;
/**缓存容量*/
private int cacheCapcity;
/**缓存 容器*/
private Map<K, Node> caches;
/**(实现双链表)链表头*/
private Node first;
/**(实现双链表)链表尾*/
private Node last;
public LRUCache(int size) {
this.currentCacheSize = 0;
this.cacheCapcity = size;
this.caches = new HashMap<K,Node>(size);
}
/***
* 利用链表和HashMap:
* 当需要插入新的数据项的时候,如果新数据项在链表中存在(一般称为命中),则把该节点移到链表头部,
* 如果不存在,则新建一个节点,放到链表头部,若缓存满了,则把链表最后一个节点删除即可。
*/
public void put(K k,V v) {
Node node = caches.get(k);
if(null == node) {
if(caches.size() >= cacheCapcity) {
caches.remove(last.key);//将最少使用的节点删除
removeLast();
}
currentCacheSize ++;
node = new Node();
node.key = k;
}
node.value = v;
moveToFirst(node);//将最新使用的节点放在链表头,表示最新使用的。
caches.put(k, node);
}
/****
* 在访问数据的时候,如果数据项在链表中存在,则把该节点移到链表头部
*/
public Object get(K k) {
Node node = caches.get(k);
if(null == node) {
return null;
}
moveToFirst(node);
return node.value;
}
/***
* 移动到链表头,表示这个节点是最新使用过的
* @author ZHEN
* 2019年5月16日
*/
private void moveToFirst(Node node) {
if(first == node) {
return;
}
if(null != node.next) {
node.next.pre = node.pre;
}
if(null != node.pre) {
node.pre.next = node.next;
}
if(node == last) {
last = last.pre;
}
if(null == first || null == last) {
first = last = node;
return;
}
node.next = first;
first.pre = node;
first = node;
first.pre = null;
}
/**
* 删除链表尾部节点 表示 删除最少使用的缓存对象
* @author ZHEN
* 2019年5月16日
*/
private void removeLast() {//链表尾不为空,则将链表尾指向null. 删除链表尾(删除最少使用的缓存对象)
if(null != last) {
last = last.pre;
if(null == last) {
first = null;
}else {
last.next = null;
}
}
}
public void clear() {
first = null;
last = null;
caches.clear();
}
public Object remove(K k) {
Node node = caches.get(k);
if(null != node) {
if(null != node.pre) {
node.pre.next = node.next;
}
if(null != node.next) {
node.next.pre = node.pre;
}
if(node == first) {
first = node.next;
}
if(node == last) {
last = node.pre;
}
}
return caches.remove(k);//HashMap remove
}
public static void main(String[] args) {
LRUCache<Object, Object> lruCache = new LRUCache<>(3);
Object remove = lruCache.remove("k1");
System.out.println(remove);
lruCache.put("k1", "v1");
lruCache.put("k2", "v2");
lruCache.put("k3", "v3");
lruCache.put("k4", "v4");
System.out.println(lruCache.caches);
System.out.println(lruCache.first);
lruCache.get("k2");
System.out.println(lruCache.first);
}
}