原理
使用HashMap和双向链表实现
每次新增数据时加到链表尾部,每次查询时移动到链表尾部。
头部是最少使用的,尾部是最近使用的。
数据满后,删除头部的数据。
代码实现
import java.util.HashMap;
/**
* 简单LRU实现,当新增数据时,如果链表长度大于预设值的最大值,则删除最少使用的。
* 链表尾部最近或者最多使用的数据,而头部则是最少使用数据
* @Description:
* @author: lhy
* @date: 2019年6月28日 上午11:37:37
*
*/
public class LRUCache {
private Node head;
private Node end;
private int limit;
private HashMap<String, Node> hashMap;//存储key与链表Node节点
public LRUCache(int limit) {
if (limit <= 0) {
throw new IllegalArgumentException("limit must > 0");
}
this.limit = limit;
hashMap = new HashMap<>();
}
public String get(String key) {
Node node = hashMap.get(key);
if (node == null) {
return null;
}
refreshNode(node);
return node.value;
}
public void put(String key, String value) {
Node node = hashMap.get(key);
if (node == null) {
if (hashMap.size() >= limit) {
// 删除最不常用的
String oldKey = removeNode(head);
hashMap.remove(oldKey);
}
Node newNode = new Node(key, value);
addNode(newNode);
hashMap.put(key, newNode);
} else {
node.value = value;
//多次赋值,我们也默认提高优先级的
refreshNode(node);
}
}
private void refreshNode(Node node) {
if (node == end) {
return;
}
removeNode(node);
addNode(node);
}
private void addNode(Node node) {
if (end != null) {
end.next = node;
node.prev = end;
}
end = node;
if (head == null) {
head = node;
}
node.next = null;
}
private String removeNode(Node node) {
if (node == end) {
end = end.prev;
} else if (node == head) {
head = head.next;
} else {
node.prev.next = node.next;
node.next.prev = node.prev;
}
return node.key;
}
private class Node {
Node prev;
Node next;
String key;
String value;
Node(String key, String value) {
this.key = key;
this.value = value;
}
}
@Override
public String toString() {
StringBuilder ret = new StringBuilder();
Node p = head;
while (p!=null){
ret.append("key:").append(p.key).append(",value:").append(p.value).append(";");
p = p.next;
}
return ret.toString();
}
public static void main(String[] args) {
LRUCache lruCache = new LRUCache(5);
lruCache.put("001","用户1");
lruCache.put("002","用户2");
lruCache.put("003","用户3");
//lruCache.put("002","用户2新");
String s = lruCache.get("002");//会把数据异动到链表尾部
System.out.println(lruCache);
//链表尾部最近或者最多使用的数据,而头部则是最少使用数据
//key:001,value:用户1;key:003,value:用户3;key:002,value:用户2;
}
}